1 | #!/usr/bin/env node
|
2 |
|
3 | 'use strict';
|
4 |
|
5 | var resolve = require('resolve-protobuf-schema');
|
6 |
|
7 | if (process.argv.length > 2) {
|
8 | console.log('\'use strict\';');
|
9 | compileMessages(resolve.sync(process.argv[2]),
|
10 | process.argv.indexOf('--browser') !== -1 ? 'window' : 'exports', {},
|
11 | process.argv.indexOf('--no-read') === -1,
|
12 | process.argv.indexOf('--no-write') === -1);
|
13 | } else {
|
14 | console.warn('Error: no path to proto file given.');
|
15 | }
|
16 |
|
17 | function compileMessage(message, parentName, enums, read, write) {
|
18 | var name = message.name,
|
19 | nameLow = name.toLowerCase(),
|
20 | nameCap = name.charAt(0).toUpperCase() + name.substr(1),
|
21 | i, field, part;
|
22 |
|
23 | console.log('\n// %s ========================================\n', name);
|
24 |
|
25 | var methods = [];
|
26 | if (read) methods.push('read: read' + nameCap);
|
27 | if (write) methods.push('write: write' + nameCap);
|
28 |
|
29 | console.log((message.messages.length ? 'var ' + name + ' = ' : '') +
|
30 | '%s.%s = {%s};\n', parentName, name, methods.join(', '));
|
31 |
|
32 | if (message.enums.length) {
|
33 | for (i = 0; i < message.enums.length; i++) {
|
34 | var en = message.enums[i];
|
35 | enums[en.name] = true;
|
36 | console.log('%s.%s = ' + JSON.stringify(en.values, null, 4) + ';\n', name, en.name);
|
37 | }
|
38 | }
|
39 |
|
40 | if (read) {
|
41 | console.log('function read%s(pbf, end) {', nameCap);
|
42 | part = 'pbf.readFields(read' + nameCap + 'Field, ' + repeatedDest(message.fields) + ', end);';
|
43 | var hasDefaults = false;
|
44 | for (i = 0; i < message.fields.length; i++) {
|
45 | field = message.fields[i];
|
46 | if (enums[field.type] && field.options.default !== undefined) {
|
47 | hasDefaults = true;
|
48 | break;
|
49 | }
|
50 | }
|
51 | if (hasDefaults) {
|
52 | console.log(' var ' + nameLow + ' = ' + part);
|
53 | for (i = 0; i < message.fields.length; i++) {
|
54 | field = message.fields[i];
|
55 | if (enums[field.type] && field.options.default !== undefined) {
|
56 | console.log(' if (%s.%s === undefined) %s.%s = ' + JSON.stringify(field.options.default) + ';',
|
57 | nameLow, field.name, nameLow, field.name);
|
58 | }
|
59 | }
|
60 | console.log(' return %s;', nameLow);
|
61 | } else {
|
62 | console.log(' return ' + part);
|
63 | }
|
64 | console.log('}\n');
|
65 |
|
66 | console.log('function read%sField(tag, %s, pbf) {', nameCap, nameLow);
|
67 |
|
68 | for (i = 0; i < message.fields.length; i++) {
|
69 | field = message.fields[i];
|
70 | part = field.repeated && !field.options.packed ? '.push(' + readMethod(field, enums) + ')' :
|
71 | ' = ' + readMethod(field, enums);
|
72 | console.log(' ' + (i ? 'else if' : 'if') + ' (tag === %d) %s.%s%s;',
|
73 | field.tag, nameLow, field.name, part);
|
74 | }
|
75 | console.log('}');
|
76 | }
|
77 |
|
78 | if (read && write) console.log('');
|
79 |
|
80 | if (write) {
|
81 | console.log('function write%s(%s, pbf) {', nameCap, nameLow);
|
82 | var iDeclared;
|
83 | for (i = 0; i < message.fields.length; i++) {
|
84 | field = message.fields[i];
|
85 | if (!iDeclared && field.repeated && !field.options.packed) {
|
86 | console.log(' var i;');
|
87 | iDeclared = true;
|
88 | }
|
89 | console.log(' if (%s.%s !== undefined) %s;', nameLow, field.name,
|
90 | writeMethod(field.tag, field.type, nameLow + '.' + field.name,
|
91 | field.repeated, field.options.packed, enums));
|
92 | }
|
93 | console.log('}');
|
94 | }
|
95 |
|
96 | compileMessages(message, name, enums, read, write);
|
97 | }
|
98 |
|
99 | function compileMessages(parent, parentName, enums, read, write) {
|
100 | for (var i = 0; i < parent.messages.length; i++) {
|
101 | compileMessage(parent.messages[i], parentName, enums, read, write);
|
102 | }
|
103 | }
|
104 |
|
105 | function repeatedDest(fields) {
|
106 | var repeated = [];
|
107 | for (var i = 0; i < fields.length; i++) {
|
108 | if (fields[i].repeated && !fields[i].options.packed) repeated.push('"' + fields[i].name + '": []');
|
109 | }
|
110 | return '{' + repeated.join(', ') + '}';
|
111 | }
|
112 |
|
113 | function readMethod(field, enums) {
|
114 | var type = field.type;
|
115 |
|
116 | var prefix = 'pbf.read';
|
117 | if (field.options.packed) prefix += 'Packed';
|
118 |
|
119 | switch (field.type) {
|
120 | case 'string': return prefix + 'String()';
|
121 | case 'float': return prefix + 'Float()';
|
122 | case 'double': return prefix + 'Double()';
|
123 | case 'bool': return prefix + 'Boolean()';
|
124 | case 'enum':
|
125 | case 'uint32':
|
126 | case 'uint64':
|
127 | case 'int32':
|
128 | case 'int64': return prefix + 'Varint()';
|
129 | case 'sint32':
|
130 | case 'sint64': return prefix + 'SVarint()';
|
131 | case 'fixed32': return prefix + 'Fixed32()';
|
132 | case 'fixed64': return prefix + 'Fixed64()';
|
133 | case 'sfixed32': return prefix + 'SFixed32()';
|
134 | case 'sfixed64': return prefix + 'SFixed64()';
|
135 | case 'bytes': return prefix + 'Bytes()';
|
136 | default: return enums[field.type] ? prefix + 'Varint()' :
|
137 | 'read' + type.charAt(0).toUpperCase() + type.substr(1) + '(pbf, pbf.readVarint() + pbf.pos)';
|
138 | }
|
139 | }
|
140 |
|
141 | function writeMethod(tag, type, name, repeated, packed, enums) {
|
142 | if (repeated && !packed) return repeatedWriteMethod(tag, type, name, enums);
|
143 |
|
144 | var prefix = 'pbf.write';
|
145 | if (packed) prefix += 'Packed';
|
146 |
|
147 | var postfix = (packed ? '' : 'Field') + '(' + tag + ', ' + name + ')';
|
148 |
|
149 | switch (type) {
|
150 | case 'string': return prefix + 'String' + postfix;
|
151 | case 'float': return prefix + 'Float' + postfix;
|
152 | case 'double': return prefix + 'Double' + postfix;
|
153 | case 'bool': return prefix + 'Boolean' + postfix;
|
154 | case 'enum':
|
155 | case 'uint32':
|
156 | case 'uint64':
|
157 | case 'int32':
|
158 | case 'int64': return prefix + 'Varint' + postfix;
|
159 | case 'sint32':
|
160 | case 'sint64': return prefix + 'SVarint' + postfix;
|
161 | case 'fixed32': return prefix + 'Fixed32' + postfix;
|
162 | case 'fixed64': return prefix + 'Fixed64' + postfix;
|
163 | case 'sfixed32': return prefix + 'SFixed32' + postfix;
|
164 | case 'sfixed64': return prefix + 'SFixed64' + postfix;
|
165 | case 'bytes': return prefix + 'Bytes' + postfix;
|
166 | default: return enums[type] ? prefix + 'Varint' + postfix :
|
167 | prefix + 'Message(' + tag + ', write' +
|
168 | type.charAt(0).toUpperCase() + type.substr(1) + ', ' + name + ')';
|
169 | }
|
170 | }
|
171 |
|
172 | function repeatedWriteMethod(tag, type, name, enums) {
|
173 | return 'for (i = 0; i < ' + name + '.length; i++) ' + writeMethod(tag, type, name + '[i]', false, false, enums);
|
174 | }
|