@@ -2,31 +2,31 @@ module.exports = static_target;
22
33static_target . private = true ;
44
5- // This file contains the beginnings of static code generation.
6- // It doesn't generate anything useful, yet, but can be used as a starting point.
5+ // Currently, this file contains initial static code for CommonJS modules.
76
87// TBD:
98// - Generate a single file or scaffold an entire project directory? Both?
109// - Targets: ES5, ES6, TypeScript? CommonJS? AMD?
11- // - Is there a need for a minimal runtime composed only of Reader/Writer/minimal util?
12- // - What about generating comments and typescript definitions for non-ts targets?
10+ // - What about generating typescript definitions for non-ts targets?
1311
1412var protobuf = require ( "../.." ) ;
1513
1614var Type = protobuf . Type ,
1715 Service = protobuf . Service ,
1816 Enum = protobuf . Enum ,
1917 Namespace = protobuf . Namespace ,
20- codegen = protobuf . util . codegen ;
18+ encoder = protobuf . encoder ,
19+ decoder = protobuf . decoder ,
20+ verifier = protobuf . verifier ,
21+ util = protobuf . util ;
2122
2223var out = [ ] ;
24+ var indent = 0 ;
2325
2426function static_target ( root , options , callback ) {
2527 tree = { } ;
2628 try {
27- out . push ( "var protobuf = require(\"protobufjs\");" ) ;
28- out . push ( "var root = exports;" ) ;
29- buildNamespace ( "root" , root ) ;
29+ buildNamespace ( "module.exports" , root ) ;
3030 callback ( null , out . join ( '\n' ) ) ;
3131 } catch ( err ) {
3232 callback ( err ) ;
@@ -35,33 +35,215 @@ function static_target(root, options, callback) {
3535 }
3636}
3737
38+ function push ( line ) {
39+ if ( line === "" )
40+ return out . push ( "" ) ;
41+ var ind = "" ;
42+ for ( var i = 0 ; i < indent ; ++ i )
43+ ind += " " ;
44+ out . push ( ind + line ) ;
45+ }
46+
47+ function pushComment ( lines ) {
48+ push ( "/**" ) ;
49+ lines . forEach ( function ( line , i ) {
50+ push ( " * " + line ) ;
51+ } ) ;
52+ push ( " */" ) ;
53+ }
54+
55+ function name ( name ) {
56+ if ( ! name )
57+ return "$root" ;
58+ return name ;
59+ }
60+
3861function buildNamespace ( ref , ns ) {
3962 if ( ! ns )
4063 return ;
64+ if ( ns . name === "" ) { // root
65+ push ( name ( ref ) + " = (function() {" ) ;
66+ ++ indent ;
67+ push ( '"use strict";' ) ;
68+ push ( "" ) ;
69+ push ( "// Minimal static codegen runtime" ) ;
70+ push ( "var $runtime = require(\"protobufjs/runtime\");" )
71+ push ( "" ) ;
72+ push ( "// Lazily resolved type references" ) ;
73+ push ( "var $lazyTypes = [];" ) ;
74+ } else {
75+ push ( "" ) ;
76+ push ( "/** @alias " + ns . fullName . substring ( 1 ) + " */" ) ;
77+ push ( name ( ref ) + "." + name ( ns . name ) + " = (function() {" ) ;
78+ ++ indent ;
79+ }
80+
81+ if ( ns instanceof Type ) {
82+ buildType ( undefined , ns ) ;
83+ } else if ( ns instanceof Service )
84+ buildService ( undefined , ns ) ;
85+ else {
86+ push ( "" ) ;
87+ push ( "/** @alias " + ( ns . name && ns . fullName . substring ( 1 ) || "exports" ) + " */" ) ;
88+ push ( "var " + name ( ns . name ) + " = {};" ) ;
89+ }
90+
4191 ns . nestedArray . forEach ( function ( nested ) {
42- if ( nested instanceof Type )
43- buildType ( ref , nested ) ;
44- else if ( nested instanceof Service )
45- buildService ( ref , nested ) ;
46- else if ( nested instanceof Enum )
47- buildEnum ( ref , nested ) ;
92+ if ( nested instanceof Enum )
93+ buildEnum ( ns . name , nested ) ;
4894 else if ( nested instanceof Namespace )
49- buildNamespace ( ref , nested ) ;
95+ buildNamespace ( ns . name , nested ) ;
96+ } ) ;
97+ push ( "" ) ;
98+ if ( ns . name === "" ) // root
99+ push ( "return $runtime.resolve($root, $lazyTypes);" ) ;
100+ else
101+ push ( "return " + name ( ns . name ) + ";" ) ;
102+ -- indent ;
103+ push ( "})();" ) ;
104+ }
105+
106+ function buildFunction ( type , functionName , gen , scope ) {
107+ var lines = gen . str ( functionName )
108+ . replace ( "(this.getCtor())" , " $root" + type . fullName )
109+ . split ( / \n / g) ;
110+ push ( name ( type . name ) + "." + functionName + " = (function() {" ) ;
111+ ++ indent ;
112+ push ( "/* eslint-disable */" ) ;
113+ Object . keys ( scope ) . forEach ( function ( key ) {
114+ push ( "var " + key + " = " + scope [ key ] + ";" ) ;
115+ } ) ;
116+ push ( "var types; $lazyTypes.push(types = [" + type . fieldsArray . map ( function ( field ) {
117+ return field . resolve ( ) . resolvedType
118+ ? JSON . stringify ( field . resolvedType . fullName . substring ( 1 ) )
119+ : "null" ;
120+ } ) . join ( ',' ) + "]);" ) ;
121+ push ( "return " + lines [ 0 ] ) ;
122+ lines . slice ( 1 ) . forEach ( function ( line ) {
123+ if ( line === '\t"use strict"' )
124+ return ;
125+ var prev = indent ;
126+ var i = 0 ;
127+ while ( line . charAt ( i ++ ) === "\t" )
128+ ++ indent ;
129+ push ( line . trim ( ) ) ;
130+ indent = prev ;
50131 } ) ;
132+ push ( "/* eslint-enable */" ) ;
133+ -- indent ;
134+ push ( "})();" ) ;
51135}
52136
53137function buildType ( ref , type ) {
54- out . push ( "" ) ;
55- out . push ( ref + "." + type . name + " = function " + type . name + "() {};" ) ; // currently just an empty function
56- buildNamespace ( ref + "." + type . name , type ) ;
138+ var fullName = type . fullName . substring ( 1 ) ;
139+
140+ push ( "" ) ;
141+ pushComment ( [
142+ "Constructs a new " + type . name + "." ,
143+ "@exports " + fullName ,
144+ "@constructor" ,
145+ "@param {Object} [properties] Properties to set"
146+ ] ) ;
147+ push ( "function " + name ( type . name ) + "(properties) {" ) ;
148+ ++ indent ;
149+ push ( "if (properties) {" ) ;
150+ ++ indent ;
151+ push ( "var keys = Object.keys(properties);" ) ;
152+ push ( "for (var i = 0; i < keys.length; ++i)" ) ;
153+ ++ indent ;
154+ push ( "this[keys[i]] = properties[keys[i]];" ) ;
155+ -- indent ;
156+ -- indent ;
157+ push ( "}" ) ;
158+ -- indent ;
159+ push ( "}" ) ;
160+ push ( "" ) ;
161+ type . fieldsArray . forEach ( function ( field ) {
162+ field . resolve ( ) ;
163+ if ( typeof field . defaultValue === 'object' && field . defaultValue )
164+ return ;
165+ push ( name ( type . name ) + ".prototype." + name ( field . name ) + " = " + JSON . stringify ( field . defaultValue ) + ";" ) ;
166+ } ) ;
167+
168+ // #encode
169+ push ( "" ) ;
170+ pushComment ( [
171+ "Encodes the specified " + type . name + "." ,
172+ "@function" ,
173+ "@param {" + fullName + "|Object} message " + type . name + " or plain object to encode" ,
174+ "@param {Writer} [writer] Writer to encode to" ,
175+ "@returns {Writer} Writer"
176+ ] ) ;
177+ buildFunction ( type , "encode" , encoder . generate ( type ) , {
178+ Writer : "$runtime.Writer" ,
179+ util : "$runtime.util"
180+ } ) ;
181+
182+ // #encodeDelimited
183+ push ( "" ) ;
184+ pushComment ( [
185+ "Encodes the specified " + type . name + ", length delimited." ,
186+ "@param {" + fullName + "|Object} message " + type . name + " or plain object to encode" ,
187+ "@param {Writer} [writer] Writer to encode to" ,
188+ "@returns {Writer} Writer"
189+ ] ) ;
190+ push ( name ( type . name ) + ".encodeDelimited = function encodeDelimited(message, writer) {" ) ;
191+ ++ indent ;
192+ push ( "return this.encode(message, writer).ldelim();" ) ;
193+ -- indent ;
194+ push ( "};" ) ;
195+
196+ // #decode
197+ push ( "" ) ;
198+ pushComment ( [
199+ "Decodes a " + type . name + " from the specified reader or buffer." ,
200+ "@function" ,
201+ "@param {Reader|Uint8Array} readerOrBuffer Reader or buffer to decode from" ,
202+ "@param {number} [length] Message length if known beforehand" ,
203+ "@returns {" + fullName + "} " + type . name
204+ ] ) ;
205+ buildFunction ( type , "decode" , decoder . generate ( type ) , {
206+ Reader : "$runtime.Reader" ,
207+ util : "$runtime.util"
208+ } ) ;
209+
210+ // #decodeDelimited
211+ push ( "" ) ;
212+ pushComment ( [
213+ "Decodes a " + type . name + " from the specified reader or buffer, length delimited." ,
214+ "@param {Reader|Uint8Array} readerOrBuffer Reader or buffer to decode from" ,
215+ "@returns {" + fullName + "} " + type . name
216+ ] ) ;
217+ push ( name ( type . name ) + ".decodeDelimited = function decodeDelimited(readerOrBuffer) {" ) ;
218+ ++ indent ;
219+ push ( "readerOrBuffer = readerOrBuffer instanceof Reader ? readerOrBuffer : Reader(readerOrBuffer);" ) ;
220+ push ( "return this.decode(readerOrBuffer, readerOrBuffer.uint32());" ) ;
221+ -- indent ;
222+ push ( "};" ) ;
223+
224+ // #verify
225+ push ( "" ) ;
226+ pushComment ( [
227+ "Verifies a " + type . name + "." ,
228+ "@param {" + fullName + "|Object} message " + type . name + " or plain object to verify" ,
229+ "@returns {?string} `null` if valid, otherwise the reason why it is not"
230+ ] ) ;
231+ buildFunction ( type , "verify" , verifier . generate ( type ) , { } ) ;
57232}
58233
59234function buildService ( ref , service ) {
60- out . push ( "" ) ;
61- out . push ( ref + "." + service . name + " = {};" ) ; // currently just an empty object
235+ push ( "" ) ;
236+ push ( name ( ref ) + "." + name ( service . name ) + " = {};" ) ; // currently just an empty object
62237}
63238
64239function buildEnum ( ref , enm ) {
65- out . push ( "" ) ;
66- out . push ( ref + "." + enm . name + " = " + JSON . stringify ( enm . values , null , "\t" ) + ";" ) ;
240+ push ( "" ) ;
241+ push ( ref + "." + enm . name + " = {" ) ;
242+ ++ indent ;
243+ push ( "" ) ;
244+ Object . keys ( enm . values ) . forEach ( function ( key ) {
245+ push ( name ( key ) + ": " + enm . values [ key ] . toString ( 10 ) + "," ) ;
246+ } ) ;
247+ -- indent ;
248+ push ( "};" ) ;
67249}
0 commit comments