@@ -31,7 +31,7 @@ exports.main = function(args, callback) {
31
31
lint : "l"
32
32
} ,
33
33
string : [ "target" , "out" , "path" , "wrap" , "root" , "lint" ] ,
34
- boolean : [ "keep-case" , "create" , "encode" , "decode" , "verify" , "convert" , "delimited" , "beautify" , "comments" , "es6" ] ,
34
+ boolean : [ "keep-case" , "create" , "encode" , "decode" , "verify" , "convert" , "delimited" , "beautify" , "comments" , "es6" , "sparse" ] ,
35
35
default : {
36
36
target : "json" ,
37
37
create : true ,
@@ -51,6 +51,9 @@ exports.main = function(args, callback) {
51
51
files = argv . _ ,
52
52
paths = typeof argv . path === "string" ? [ argv . path ] : argv . path || [ ] ;
53
53
54
+ // protobuf.js package directory contains additional, otherwise non-bundled google types
55
+ paths . push ( path . relative ( process . cwd ( ) , path . join ( __dirname , ".." ) ) || "." ) ;
56
+
54
57
if ( ! files . length ) {
55
58
var descs = Object . keys ( targets ) . filter ( function ( key ) { return ! targets [ key ] . private ; } ) . map ( function ( key ) {
56
59
return " " + util . pad ( key , 14 , true ) + targets [ key ] . description ;
@@ -71,6 +74,8 @@ exports.main = function(args, callback) {
71
74
"" ,
72
75
" -o, --out Saves to a file instead of writing to stdout." ,
73
76
"" ,
77
+ " --sparse Exports only those types referenced from a main file (experimental)." ,
78
+ "" ,
74
79
chalk . bold . gray ( " Module targets only:" ) ,
75
80
"" ,
76
81
" -w, --wrap Specifies the wrapper to use. Also accepts a path to require a custom wrapper." ,
@@ -124,17 +129,33 @@ exports.main = function(args, callback) {
124
129
125
130
var root = new protobuf . Root ( ) ;
126
131
132
+ var mainFiles = [ ] ;
133
+
127
134
// Search include paths when resolving imports
128
135
root . resolvePath = function pbjsResolvePath ( origin , target ) {
129
- var filepath = protobuf . util . path . resolve ( origin , target ) ;
130
- if ( fs . existsSync ( filepath ) )
131
- return filepath ;
136
+ var normOrigin = protobuf . util . path . normalize ( origin ) ,
137
+ normTarget = protobuf . util . path . normalize ( target ) ;
138
+ if ( ! normOrigin )
139
+ mainFiles . push ( normTarget ) ;
140
+
141
+ var resolved = protobuf . util . path . resolve ( normOrigin , normTarget , true ) ;
142
+ var idx = resolved . lastIndexOf ( "google/protobuf/" ) ;
143
+ if ( idx > - 1 ) {
144
+ var altname = resolved . substring ( idx ) ;
145
+ if ( altname in protobuf . common )
146
+ resolved = altname ;
147
+ }
148
+
149
+ if ( fs . existsSync ( resolved ) )
150
+ return resolved ;
151
+
132
152
for ( var i = 0 ; i < paths . length ; ++ i ) {
133
- var ifilepath = protobuf . util . path . resolve ( paths [ i ] + "/" , target ) ;
134
- if ( fs . existsSync ( ifilepath ) )
135
- return ifilepath ;
153
+ var iresolved = protobuf . util . path . resolve ( paths [ i ] + "/" , target ) ;
154
+ if ( fs . existsSync ( iresolved ) )
155
+ return iresolved ;
136
156
}
137
- return filepath ;
157
+
158
+ return resolved ;
138
159
} ;
139
160
140
161
// Use es6 syntax if not explicitly specified on the command line and the es6 wrapper is used
@@ -153,19 +174,28 @@ exports.main = function(args, callback) {
153
174
} ) ;
154
175
process . stdin . on ( "end" , function ( ) {
155
176
var source = Buffer . concat ( data ) . toString ( "utf8" ) ;
156
- if ( source . charAt ( 0 ) !== "{" ) {
157
- protobuf . parse ( source , root , parseOptions ) ;
158
- } else {
159
- var json = JSON . parse ( source ) ;
160
- root . setOptions ( json . options ) . addJSON ( json ) ;
177
+ try {
178
+ if ( source . charAt ( 0 ) !== "{" ) {
179
+ protobuf . parse . filename = "-" ;
180
+ protobuf . parse ( source , root , parseOptions ) ;
181
+ } else {
182
+ var json = JSON . parse ( source ) ;
183
+ root . setOptions ( json . options ) . addJSON ( json ) ;
184
+ }
185
+ callTarget ( ) ;
186
+ } catch ( err ) {
187
+ if ( callback )
188
+ return callback ( err ) ;
189
+ throw err ;
161
190
}
162
- callTarget ( ) ;
163
191
} ) ;
164
192
165
193
// Load from disk
166
194
} else {
167
195
try {
168
- root . loadSync ( files , parseOptions ) ; // sync is deterministic while async is not
196
+ root . loadSync ( files , parseOptions ) . resolveAll ( ) ; // sync is deterministic while async is not
197
+ if ( argv . sparse )
198
+ sparsify ( root ) ;
169
199
callTarget ( ) ;
170
200
} catch ( err ) {
171
201
if ( callback ) {
@@ -176,6 +206,62 @@ exports.main = function(args, callback) {
176
206
}
177
207
}
178
208
209
+ function markReferenced ( tobj ) {
210
+ tobj . referenced = true ;
211
+ // also mark a type's fields and oneofs
212
+ if ( tobj . fieldsArray )
213
+ tobj . fieldsArray . forEach ( function ( fobj ) {
214
+ fobj . referenced = true ;
215
+ } ) ;
216
+ if ( tobj . oneofsArray )
217
+ tobj . oneofsArray . forEach ( function ( oobj ) {
218
+ oobj . referenced = true ;
219
+ } ) ;
220
+ // also mark an extension field's extended type, but not its (other) fields
221
+ if ( tobj . extensionField )
222
+ tobj . extensionField . parent . referenced = true ;
223
+ }
224
+
225
+ function sparsify ( root ) {
226
+
227
+ // 1. mark directly or indirectly referenced objects
228
+ util . traverse ( root , function ( obj ) {
229
+ if ( ! obj . filename )
230
+ return ;
231
+ if ( mainFiles . indexOf ( obj . filename ) > - 1 )
232
+ util . traverseResolved ( obj , markReferenced ) ;
233
+ } ) ;
234
+
235
+ // 2. empty unreferenced objects
236
+ util . traverse ( root , function ( obj ) {
237
+ var parent = obj . parent ;
238
+ if ( ! parent || obj . referenced ) // root or referenced
239
+ return ;
240
+ // remove unreferenced namespaces
241
+ if ( obj instanceof protobuf . Namespace ) {
242
+ var hasReferenced = false ;
243
+ util . traverse ( obj , function ( iobj ) {
244
+ if ( iobj . referenced )
245
+ hasReferenced = true ;
246
+ } ) ;
247
+ if ( hasReferenced ) { // replace with plain namespace if a namespace subclass
248
+ if ( obj instanceof protobuf . Type || obj instanceof protobuf . Service ) {
249
+ var robj = new protobuf . Namespace ( obj . name , obj . options ) ;
250
+ robj . nested = obj . nested ;
251
+ parent . add ( robj ) ;
252
+ }
253
+ } else // remove completely if nothing inside is referenced
254
+ parent . remove ( obj ) ;
255
+
256
+ // remove everything else unreferenced
257
+ } else if ( ! ( obj instanceof protobuf . Namespace ) )
258
+ parent . remove ( obj ) ;
259
+ } ) ;
260
+
261
+ // 3. validate that everything is fine
262
+ root . resolveAll ( ) ;
263
+ }
264
+
179
265
function callTarget ( ) {
180
266
target ( root , argv , function targetCallback ( err , output ) {
181
267
if ( err ) {
0 commit comments