protoc.js 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545
  1. const protoc = {};
  2. const fs = require('fs');
  3. const path = require('path');
  4. protoc.Object = class {
  5. constructor(parent, name) {
  6. this.parent = parent;
  7. this.name = name;
  8. this.options = new Map();
  9. }
  10. get fullName() {
  11. const path = [ this.name ];
  12. let context = this.parent;
  13. while (context) {
  14. path.unshift(context.name);
  15. context = context.parent;
  16. }
  17. return path.join('.');
  18. }
  19. };
  20. protoc.Namespace = class extends protoc.Object {
  21. constructor(parent, name) {
  22. super(parent, name);
  23. this.children = new Map();
  24. if (!(this instanceof protoc.Root || this instanceof protoc.PrimitiveType)) {
  25. if (parent.get(this.name)) {
  26. throw new protoc.Error("Duplicate name '" + this.name + "' in '" + parent.name + "'.");
  27. }
  28. parent.children.set(this.name, this);
  29. }
  30. }
  31. defineNamespace(path) {
  32. path = path.split('.');
  33. if (path && path.length > 0 && path[0] === '') {
  34. throw new protoc.Error('Invalid path.');
  35. }
  36. let parent = this;
  37. while (path.length > 0) {
  38. const part = path.shift();
  39. if (parent.children && parent.children.get(part)) {
  40. parent = parent.children.get(part);
  41. if (!(parent instanceof protoc.Namespace)) {
  42. throw new protoc.Error('Invalid path.');
  43. }
  44. }
  45. else {
  46. parent = new protoc.Namespace(parent, part);
  47. }
  48. }
  49. return parent;
  50. }
  51. defineType(name) {
  52. const parts = name.split('.');
  53. const typeName = parts.pop();
  54. const parent = this.defineNamespace(parts.join('.'));
  55. const type = parent.get(name);
  56. if (type) {
  57. if (type instanceof protoc.Type) {
  58. return type;
  59. }
  60. throw new protoc.Error('Invalid type');
  61. }
  62. return new protoc.Type(parent, typeName);
  63. }
  64. get(name) {
  65. return this.children.get(name) || null;
  66. }
  67. find(path, filterType, parentAlreadyChecked) {
  68. if (path.length === 0) {
  69. return this;
  70. }
  71. if (path[0] === '') {
  72. return this.root.find(path.slice(1), filterType);
  73. }
  74. let found = this.get(path[0]);
  75. if (found) {
  76. if (path.length === 1) {
  77. if (found instanceof filterType) {
  78. return found;
  79. }
  80. }
  81. else if (found instanceof protoc.Namespace && (found = found.find(path.slice(1), filterType, true))) {
  82. return found;
  83. }
  84. }
  85. else {
  86. for (const child of this.children.values()) {
  87. if (child instanceof protoc.Namespace && (found = child.find(path, filterType, true))) {
  88. return found;
  89. }
  90. }
  91. }
  92. if (!this.parent || parentAlreadyChecked) {
  93. return null;
  94. }
  95. return this.parent.find(path, filterType);
  96. }
  97. findType(path) {
  98. const type = this.find(path.split('.'), protoc.Type);
  99. if (!type) {
  100. throw new protoc.Error("Type or enum '" + path + "' not found in '" + this.name + "'.");
  101. }
  102. return type;
  103. }
  104. static isReservedId(reserved, id) {
  105. if (reserved) {
  106. for (let i = 0; i < reserved.length; ++i) {
  107. if (typeof reserved[i] !== 'string' && reserved[i][0] <= id && reserved[i][1] > id) {
  108. return true;
  109. }
  110. }
  111. }
  112. return false;
  113. }
  114. static isReservedName(reserved, name) {
  115. if (reserved) {
  116. for (let i = 0; i < reserved.length; ++i) {
  117. if (reserved[i] === name) {
  118. return true;
  119. }
  120. }
  121. }
  122. return false;
  123. }
  124. };
  125. protoc.Root = class extends protoc.Namespace {
  126. constructor(alias, paths, files) {
  127. super(null, '');
  128. this.alias = alias;
  129. this._files = new Set();
  130. this._library = new Map();
  131. this._library.set('google/protobuf/any.proto', () => {
  132. const type = this.defineType('google.protobuf.Any');
  133. new protoc.Field(type, 'type_url', 1, 'string');
  134. new protoc.Field(type, 'value', 2, 'bytes');
  135. });
  136. this._library.set('google/protobuf/wrappers.proto', () => {
  137. new protoc.Field(this.defineType('google.protobuf.BoolValue'), 'value', 1, 'bool');
  138. });
  139. this.load(paths, files);
  140. }
  141. load(paths, files) {
  142. for (const file of files) {
  143. const resolved = this._resolve(file, '', paths);
  144. if (resolved) {
  145. this._loadFile(paths, resolved);
  146. }
  147. else {
  148. throw new protoc.Error("File '" + file + "' not found.");
  149. }
  150. }
  151. return this;
  152. }
  153. _loadFile(paths, file, weak) {
  154. if (!this._files.has(file)) {
  155. this._files.add(file);
  156. if (!this._library.has(file)) {
  157. try {
  158. this._parseFile(paths, file);
  159. }
  160. catch (err) {
  161. if (!weak) {
  162. throw err;
  163. }
  164. }
  165. }
  166. else {
  167. const callback = this._library.get(file);
  168. callback();
  169. }
  170. }
  171. }
  172. _parseFile(paths, file) {
  173. const source = fs.readFileSync(file, 'utf-8');
  174. const parser = new protoc.Parser(source, file, this);
  175. const parsed = parser.parse();
  176. for (const item of parsed.imports) {
  177. const resolved = this._resolve(item, file, paths);
  178. if (!resolved) {
  179. throw new protoc.Error("File '" + item + "' not found.");
  180. }
  181. this._loadFile(paths, resolved);
  182. }
  183. for (const item of parsed.weakImports) {
  184. const resolved = this._resolve(item, file, paths);
  185. if (resolved) {
  186. this._loadFile(paths, resolved);
  187. }
  188. }
  189. }
  190. _resolve(target, source, paths) {
  191. const file = path.resolve(source, target);
  192. const posix = file.split(path.sep).join(path.posix.sep);
  193. const index = posix.lastIndexOf('google/protobuf/');
  194. if (index > -1) {
  195. const name = posix.substring(index);
  196. if (this._library.has(name)) {
  197. return name;
  198. }
  199. }
  200. if (fs.existsSync(file)) {
  201. return file;
  202. }
  203. for (const dir of paths) {
  204. const file = path.resolve(dir, target);
  205. if (fs.existsSync(file)) {
  206. return file;
  207. }
  208. }
  209. return null;
  210. }
  211. };
  212. protoc.Type = class extends protoc.Namespace {
  213. constructor(parent, name) {
  214. super(parent, name);
  215. this.fields = new Map();
  216. this.oneofs = new Map();
  217. this.extensions = [];
  218. this.reserved = [];
  219. }
  220. get(name) {
  221. return this.fields.get(name) || this.oneofs.get(name) || this.children.get(name) || null;
  222. }
  223. };
  224. protoc.Enum = class extends protoc.Type {
  225. constructor(parent, name) {
  226. super(parent, name);
  227. this.valuesById = {};
  228. this.values = {};
  229. this.reserved = [];
  230. }
  231. add(name, id) {
  232. if (!Number.isInteger(id)) {
  233. throw new protoc.Error('Identifier must be an integer.');
  234. }
  235. if (this.values[name] !== undefined) {
  236. throw new protoc.Error("Duplicate name '" + name + "' in '" + this.name + "'.");
  237. }
  238. if (protoc.Namespace.isReservedId(this.reserved, id)) {
  239. throw new protoc.Error("Identifier '" + id + "' is reserved in '" + this.name + "'.");
  240. }
  241. if (protoc.Namespace.isReservedName(this.reserved, name)) {
  242. throw new protoc.Error("Name '" + name + "' is reserved in '" + this.name + "'.");
  243. }
  244. if (this.valuesById[id] !== undefined) {
  245. if (!this.options.has('allow_alias')) {
  246. throw new protoc.Error("Duplicate identifier '" + id + "' in '" + this.name + "'.");
  247. }
  248. }
  249. else {
  250. this.valuesById[id] = name;
  251. }
  252. this.values[name] = id;
  253. }
  254. };
  255. protoc.PrimitiveType = class extends protoc.Type {
  256. constructor(name, long, mapKey, packed, defaultValue) {
  257. super(null, name);
  258. this.long = long;
  259. this.mapKey = mapKey;
  260. this.packed = packed;
  261. this.defaultValue = defaultValue;
  262. }
  263. static get(name) {
  264. if (!this._map) {
  265. this._map = new Map();
  266. const register = (type) => this._map.set(type.name, type);
  267. register(new protoc.PrimitiveType('double', false, false, true, 0));
  268. register(new protoc.PrimitiveType('float', false, false, true, 0));
  269. register(new protoc.PrimitiveType('int32', false, true, true, 0));
  270. register(new protoc.PrimitiveType('uint32', false, true, true, 0));
  271. register(new protoc.PrimitiveType('sint32', false, true, true, 0));
  272. register(new protoc.PrimitiveType('fixed32', false, true, true, 0));
  273. register(new protoc.PrimitiveType('sfixed32', false, true, true, 0));
  274. register(new protoc.PrimitiveType('int64', true, true, true, 0));
  275. register(new protoc.PrimitiveType('uint64', true, true, true, 0));
  276. register(new protoc.PrimitiveType('sint64', true, true, true, 0));
  277. register(new protoc.PrimitiveType('fixed64', true, true, true, 0));
  278. register(new protoc.PrimitiveType('sfixed64', true, true, true, 0));
  279. register(new protoc.PrimitiveType('bool', false, true, true, false));
  280. register(new protoc.PrimitiveType('string', false, true, false, ''));
  281. register(new protoc.PrimitiveType('bytes', false, true, false, []));
  282. }
  283. return this._map.get(name);
  284. }
  285. };
  286. protoc.Field = class extends protoc.Object {
  287. constructor(parent, name, id, type, rule, extend) {
  288. super(parent instanceof protoc.OneOf ? parent.parent : parent, name);
  289. if (!Number.isInteger(id) || id < 0) {
  290. throw new protoc.Error('Identifier must be a non-negative integer.');
  291. }
  292. if (rule && !/^required|optional|repeated$/.test(rule = rule.toString().toLowerCase())) {
  293. throw new protoc.Error('Rule must be a string.');
  294. }
  295. this.id = id;
  296. this._type = type;
  297. this.rule = rule && rule !== 'optional' ? rule : undefined;
  298. this.extend = extend;
  299. this.required = rule === 'required';
  300. this.repeated = rule === 'repeated';
  301. if (parent instanceof protoc.OneOf) {
  302. this.partOf = parent;
  303. parent.oneof.set(this.name, this);
  304. parent = parent.parent;
  305. }
  306. if (parent.get(this.name)) {
  307. throw new protoc.Error("Duplicate name '" + this.name + "' in '" + parent.name + "'.");
  308. }
  309. if (protoc.Namespace.isReservedId(parent.reserved, this.id)) {
  310. throw new protoc.Error("Identifier '" + this.id + "' is reserved in '" + parent.name + "'.");
  311. }
  312. if (protoc.Namespace.isReservedName(parent.reserved, this.name)) {
  313. throw new protoc.Error("Name '" + this.name + "' is reserved in '" + parent.name + "'.");
  314. }
  315. parent.fields.set(this.name, this);
  316. }
  317. get type() {
  318. if (typeof this._type === 'string') {
  319. this._type = protoc.PrimitiveType.get(this._type) || this.parent.findType(this._type);
  320. }
  321. return this._type;
  322. }
  323. get defaultValue() {
  324. const type = this.type;
  325. let value = null;
  326. if (type instanceof protoc.PrimitiveType) {
  327. value = type.defaultValue;
  328. }
  329. else if (type instanceof protoc.Enum) {
  330. value = type.values[Object.keys(type.values)[0]];
  331. }
  332. if (this.options.has('default')) {
  333. value = this.options.get('default');
  334. if (type instanceof protoc.Enum && typeof value === 'string') {
  335. value = type.values[value];
  336. }
  337. }
  338. if (type === 'bytes' && typeof value === 'string') {
  339. throw new protoc.Error('Unsupported bytes field.');
  340. }
  341. return value;
  342. }
  343. };
  344. protoc.OneOf = class extends protoc.Object {
  345. constructor(parent, name) {
  346. super(parent, name);
  347. this.oneof = new Map();
  348. if (parent.get(this.name)) {
  349. throw new protoc.Error("Duplicate name '" + this.name + "' in '" + parent.name + "'.");
  350. }
  351. parent.oneofs.set(this.name, this);
  352. }
  353. };
  354. protoc.MapField = class extends protoc.Field {
  355. constructor(parent, name, id, keyType, type) {
  356. super(parent, name, id, type);
  357. this.keyType = protoc.PrimitiveType.get(keyType);
  358. }
  359. };
  360. protoc.Parser = class {
  361. constructor(text, file, root) {
  362. this._context = root;
  363. this._tokenizer = new protoc.Parser.Tokenizer(text, file);
  364. this._head = true;
  365. this._imports = [];
  366. this._weakImports = [];
  367. }
  368. parse() {
  369. let token;
  370. while ((token = this._tokenizer.next()) !== null) {
  371. switch (token) {
  372. case 'package':
  373. if (!this._head) {
  374. throw this._parseError(token);
  375. }
  376. this._parsePackage();
  377. break;
  378. case 'import':
  379. if (!this._head) {
  380. throw this._parseError(token);
  381. }
  382. this._parseImport();
  383. break;
  384. case 'syntax':
  385. if (!this._head) {
  386. throw this._parseError(token);
  387. }
  388. this._parseSyntax();
  389. break;
  390. case 'option':
  391. this._parseOption(this._context, token);
  392. this._tokenizer.expect(';');
  393. break;
  394. default:
  395. if (this._parseCommon(this._context, token)) {
  396. this._head = false;
  397. continue;
  398. }
  399. throw this._parseError(token);
  400. }
  401. }
  402. return { package: this._package, imports: this._imports, weakImports: this._weakImports };
  403. }
  404. _parseId(token, acceptNegative) {
  405. switch (token) {
  406. case 'max':
  407. case 'Max':
  408. case 'MAX':
  409. return 0x1fffffff;
  410. case '0':
  411. return 0;
  412. default: {
  413. if (!acceptNegative && token.charAt(0) === "-") {
  414. throw this._parseError(token, 'id');
  415. }
  416. if (/^-?[1-9][0-9]*$/.test(token)) {
  417. return parseInt(token, 10);
  418. }
  419. if (/^-?0[x][0-9a-fA-F]+$/.test(token)) {
  420. return parseInt(token, 16);
  421. }
  422. if (/^-?0[0-7]+$/.test(token)) {
  423. return parseInt(token, 8);
  424. }
  425. throw this._parseError(token, 'id');
  426. }
  427. }
  428. }
  429. _parsePackage() {
  430. if (this._package) {
  431. throw this._parseError("package");
  432. }
  433. this._package = this._tokenizer.next();
  434. if (!protoc.Parser._isTypeReference(this._package)) {
  435. throw this._parseError(this._package, 'name');
  436. }
  437. this._context = this._context.defineNamespace(this._package);
  438. this._tokenizer.expect(";");
  439. }
  440. _parseImport() {
  441. let token = this._tokenizer.peek();
  442. let whichImports;
  443. switch (token) {
  444. case "weak":
  445. whichImports = this._weakImports;
  446. this._tokenizer.next();
  447. break;
  448. case "public":
  449. this._tokenizer.next();
  450. // eslint-disable-line no-fallthrough
  451. default:
  452. whichImports = this._imports;
  453. break;
  454. }
  455. token = this._readString();
  456. this._tokenizer.expect(";");
  457. whichImports.push(token);
  458. }
  459. _parseSyntax() {
  460. this._tokenizer.expect("=");
  461. this._syntax = this._readString();
  462. if (this._syntax !== 'proto2' && this._syntax !== 'proto3') {
  463. throw this._parseError(this._syntax, 'syntax');
  464. }
  465. this._tokenizer.expect(";");
  466. }
  467. _parseCommon(parent, token) {
  468. switch (token) {
  469. case 'option':
  470. this._parseOption(parent, token);
  471. this._tokenizer.expect(";");
  472. return true;
  473. case 'message':
  474. this._parseType(parent, token);
  475. return true;
  476. case 'enum':
  477. this._parseEnum(parent, token);
  478. return true;
  479. case 'extend':
  480. this._parseExtend(parent, token);
  481. return true;
  482. case 'service':
  483. throw new protoc.Error("Keyword '" + token + "' is not supported" + this._tokenizer.location());
  484. default:
  485. return false;
  486. }
  487. }
  488. _ifBlock(obj, ifCallback, elseCallback) {
  489. if (obj) {
  490. obj.file = this._file;
  491. }
  492. if (this._tokenizer.eat("{")) {
  493. let token;
  494. while ((token = this._tokenizer.next()) !== "}") {
  495. ifCallback(token);
  496. }
  497. this._tokenizer.eat(";");
  498. }
  499. else {
  500. if (elseCallback) {
  501. elseCallback();
  502. }
  503. this._tokenizer.expect(";");
  504. }
  505. }
  506. _parseType(parent, token) {
  507. token = this._tokenizer.next();
  508. if (!protoc.Parser._isName(token)) {
  509. throw this._parseError(token, 'type');
  510. }
  511. const type = new protoc.Type(parent, token);
  512. const self = this;
  513. this._ifBlock(type, function(token) {
  514. if (self._parseCommon(type, token)) {
  515. return;
  516. }
  517. switch (token) {
  518. case 'map':
  519. self._parseMapField(type, token);
  520. break;
  521. case 'required':
  522. case 'optional':
  523. case 'repeated':
  524. self._parseField(type, token);
  525. break;
  526. case 'oneof':
  527. self._parseOneOf(type, token);
  528. break;
  529. case 'reserved':
  530. self._readRanges(type.reserved, true);
  531. break;
  532. case 'extensions':
  533. self._readRanges(type.extensions);
  534. break;
  535. // throw new protoc.Error("Keyword 'extensions' is not supported" + self._tokenizer.location());
  536. default:
  537. if (self._syntax !== 'proto3' || !protoc.Parser._isTypeReference(token)) {
  538. throw self._parseError(token);
  539. }
  540. self._tokenizer.push(token);
  541. self._parseField(type, 'optional');
  542. break;
  543. }
  544. });
  545. }
  546. _parseField(parent, rule, extend) {
  547. const type = this._tokenizer.next();
  548. if (type === "group") {
  549. this._parseGroup(parent, rule);
  550. return;
  551. }
  552. if (!protoc.Parser._isTypeReference(type)) {
  553. throw this._parseError(type, 'type');
  554. }
  555. const name = this._tokenizer.next();
  556. if (!protoc.Parser._isName(name)) {
  557. throw this._parseError(name, 'name');
  558. }
  559. this._tokenizer.expect("=");
  560. const id = this._parseId(this._tokenizer.next());
  561. const field = new protoc.Field(parent, name, id, type, rule, extend);
  562. const self = this;
  563. this._ifBlock(field, function (token) {
  564. if (token === "option") {
  565. self._parseOption(field, token);
  566. self._tokenizer.expect(";");
  567. }
  568. else {
  569. throw self._parseError(token);
  570. }
  571. }, function () {
  572. self._parseInlineOptions(field);
  573. });
  574. }
  575. _parseGroup(parent, rule) {
  576. let name = this._tokenizer.next();
  577. if (!protoc.Parser._isName(name)) {
  578. throw this._parseError(name, 'name');
  579. }
  580. const fieldName = name.charAt(0).toLowerCase() + name.substring(1);
  581. if (name === fieldName) {
  582. name = name.charAt(0).toUpperCase() + name.substring(1);
  583. }
  584. this._tokenizer.expect("=");
  585. const id = this._parseId(this._tokenizer.next());
  586. const type = new protoc.Type(name);
  587. type.group = true;
  588. const field = new protoc.Field(parent, fieldName, id, name, rule);
  589. field.file = this._file;
  590. this._ifBlock(type, function parseGroup_block(token) {
  591. switch (token) {
  592. case "option":
  593. self._parseOption(type, token);
  594. self._tokenizer.expect(";");
  595. break;
  596. case "required":
  597. case "optional":
  598. case "repeated":
  599. self._parseField(type, token);
  600. break;
  601. default:
  602. throw self._parseError(token); // there are no groups with proto3 semantics
  603. }
  604. });
  605. parent.add(type).add(field);
  606. }
  607. _parseMapField(parent) {
  608. this._tokenizer.expect("<");
  609. const keyType = this._tokenizer.next();
  610. const resolvedKeyType = protoc.PrimitiveType.get(keyType);
  611. if (!resolvedKeyType || !resolvedKeyType.mapKey) {
  612. throw this._parseError(keyType, 'type');
  613. }
  614. this._tokenizer.expect(",");
  615. const valueType = this._tokenizer.next();
  616. if (!protoc.Parser._isTypeReference(valueType)) {
  617. throw this._parseError(valueType, 'type');
  618. }
  619. this._tokenizer.expect(">");
  620. const name = this._tokenizer.next();
  621. if (!protoc.Parser._isName(name)) {
  622. throw this._parseError(name, 'name');
  623. }
  624. this._tokenizer.expect("=");
  625. const id = this._parseId(this._tokenizer.next());
  626. const field = new protoc.MapField(parent, name, id, keyType, valueType);
  627. const self = this;
  628. this._ifBlock(field, function(token) {
  629. if (token === "option") {
  630. self._parseOption(field, token);
  631. self._tokenizer.expect(";");
  632. }
  633. else {
  634. throw self._parseError(token);
  635. }
  636. }, function() {
  637. self._parseInlineOptions(field);
  638. });
  639. }
  640. _parseOneOf(parent, token) {
  641. token = this._tokenizer.next();
  642. if (!protoc.Parser._isName(token)) {
  643. throw this._parseError(token, 'name');
  644. }
  645. const oneof = new protoc.OneOf(parent, token);
  646. const self = this;
  647. this._ifBlock(oneof, function(token) {
  648. if (token === "option") {
  649. self._parseOption(oneof, token);
  650. self._tokenizer.expect(";");
  651. }
  652. else {
  653. self._tokenizer.push(token);
  654. self._parseField(oneof, 'optional');
  655. }
  656. });
  657. }
  658. _parseEnum(parent, token) {
  659. token = this._tokenizer.next();
  660. if (!protoc.Parser._isName(token)) {
  661. throw this._parseError(token, 'name');
  662. }
  663. const obj = new protoc.Enum(parent, token);
  664. const self = this;
  665. this._ifBlock(obj, function(token) {
  666. switch(token) {
  667. case "option":
  668. self._parseOption(obj, token);
  669. self._tokenizer.expect(";");
  670. break;
  671. case "reserved":
  672. self._readRanges(obj.reserved, true);
  673. break;
  674. default:
  675. self._parseEnumValue(obj, token);
  676. break;
  677. }
  678. });
  679. }
  680. _parseEnumValue(parent, token) {
  681. if (!protoc.Parser._isName(token)) {
  682. throw this._parseError(token, 'name');
  683. }
  684. this._tokenizer.expect("=");
  685. const value = this._parseId(this._tokenizer.next(), true);
  686. const dummy = {};
  687. const self = this;
  688. this._ifBlock(dummy, function(token) {
  689. if (token === "option") {
  690. self._parseOption(dummy, token); // skip
  691. self._tokenizer.expect(";");
  692. }
  693. else {
  694. throw self._parseError(token);
  695. }
  696. }, function() {
  697. self._parseInlineOptions(dummy); // skip
  698. });
  699. parent.add(token, value);
  700. }
  701. _parseExtend(parent, token) {
  702. token = this._tokenizer.next();
  703. if (!protoc.Parser._isTypeReference(token)) {
  704. throw this._parseError(token, 'reference');
  705. }
  706. const reference = token;
  707. const self = this;
  708. this._ifBlock(null, function(token) {
  709. switch (token) {
  710. case "required":
  711. case "repeated":
  712. case "optional":
  713. self._parseField(parent, token, reference);
  714. break;
  715. default:
  716. if (!self._syntax !== 'proto3' || !protoc.Parser._isTypeReference(token)) {
  717. throw self._parseError(token);
  718. }
  719. self._tokenizer.push(token);
  720. self._parseField(parent, 'optional', reference);
  721. break;
  722. }
  723. });
  724. }
  725. _parseOption(parent, token) {
  726. const custom = this._tokenizer.eat("(");
  727. token = this._tokenizer.next();
  728. if (!protoc.Parser._isTypeReference(token)) {
  729. throw this._parseError(token, 'name');
  730. }
  731. let name = token;
  732. if (custom) {
  733. this._tokenizer.expect(")");
  734. name = "(" + name + ")";
  735. token = this._tokenizer.peek();
  736. if (/^(?:\.[a-zA-Z_][a-zA-Z_0-9]*)+$/.test(token)) {
  737. name += token;
  738. this._tokenizer.next();
  739. }
  740. }
  741. this._tokenizer.expect("=");
  742. this._parseOptionValue(parent, name);
  743. }
  744. _parseOptionValue(parent, name) {
  745. if (this._tokenizer.eat('{')) {
  746. while (!this._tokenizer.eat('}')) {
  747. const token = this._tokenizer.next();
  748. if (!protoc.Parser._isName(token)) {
  749. throw this._parseError(token, 'name');
  750. }
  751. if (this._tokenizer.peek() === '{') {
  752. this._parseOptionValue(parent, name + '.' + token);
  753. }
  754. else {
  755. this._tokenizer.expect(':');
  756. if (this._tokenizer.peek() === '{') {
  757. this._parseOptionValue(parent, name + '.' + token);
  758. }
  759. else {
  760. parent.options.set(name + '.' + token, this._readValue());
  761. }
  762. }
  763. this._tokenizer.eat(',');
  764. }
  765. }
  766. else {
  767. parent.options.set(name, this._readValue());
  768. }
  769. }
  770. _parseInlineOptions(parent) {
  771. if (this._tokenizer.eat('[')) {
  772. do {
  773. this._parseOption(parent, 'option');
  774. }
  775. while (this._tokenizer.eat(','));
  776. this._tokenizer.expect(']');
  777. }
  778. return parent;
  779. }
  780. _readString() {
  781. const values = [];
  782. let token;
  783. do {
  784. if ((token = this._tokenizer.next()) !== '"' && token !== "'") {
  785. throw this._parseError(token);
  786. }
  787. values.push(this._tokenizer.next());
  788. this._tokenizer.expect(token);
  789. token = this._tokenizer.peek();
  790. }
  791. while (token === '"' || token === "'");
  792. return values.join('');
  793. }
  794. _readValue() {
  795. const token = this._tokenizer.next();
  796. switch (token) {
  797. case "'":
  798. case '"':
  799. this._tokenizer.push(token);
  800. return this._readString();
  801. case 'true':
  802. case 'TRUE':
  803. return true;
  804. case 'false':
  805. case 'FALSE':
  806. return false;
  807. default: {
  808. const value = this._parseNumber(token);
  809. if (value !== undefined) {
  810. return value;
  811. }
  812. if (protoc.Parser._isTypeReference(token)) {
  813. return token;
  814. }
  815. throw this._parseError(token, 'value');
  816. }
  817. }
  818. }
  819. _readRanges(target, acceptStrings) {
  820. do {
  821. let token;
  822. if (acceptStrings && ((token = this._tokenizer.peek()) === '"' || token === "'")) {
  823. target.push(this._readString());
  824. }
  825. else {
  826. const start = this._parseId(this._tokenizer.next());
  827. const end = this._tokenizer.eat('to') ? this._parseId(this._tokenizer.next()) : start;
  828. target.push([ start, end ]);
  829. }
  830. }
  831. while (this._tokenizer.eat(','));
  832. this._tokenizer.expect(';');
  833. }
  834. _parseNumber(token) {
  835. let sign = 1;
  836. if (token.charAt(0) === '-') {
  837. sign = -1;
  838. token = token.substring(1);
  839. }
  840. switch (token) {
  841. case 'inf':
  842. case 'INF':
  843. case 'Inf': {
  844. return sign * Infinity;
  845. }
  846. case 'nan':
  847. case 'NAN':
  848. case 'Nan':
  849. case 'NaN': {
  850. return NaN;
  851. }
  852. case '0': {
  853. return 0;
  854. }
  855. default: {
  856. if (/^[1-9][0-9]*$/.test(token)) {
  857. return sign * parseInt(token, 10);
  858. }
  859. if (/^0[x][0-9a-fA-F]+$/.test(token)) {
  860. return sign * parseInt(token, 16);
  861. }
  862. if (/^0[0-7]+$/.test(token)) {
  863. return sign * parseInt(token, 8);
  864. }
  865. if (/^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/.test(token)) {
  866. return sign * parseFloat(token);
  867. }
  868. return undefined;
  869. }
  870. }
  871. }
  872. static _isName(value) {
  873. return /^[a-zA-Z_][a-zA-Z_0-9]*$/.test(value);
  874. }
  875. static _isTypeReference(value) {
  876. return /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/.test(value);
  877. }
  878. _parseError(token, name) {
  879. name = name || 'token';
  880. const location = this._tokenizer.location();
  881. return new protoc.Error("Invalid " + name + " '" + token + "'" + location + ".");
  882. }
  883. };
  884. protoc.Parser.Tokenizer = class {
  885. constructor(text, file) {
  886. this._text = text;
  887. this._file = file;
  888. this._position = 0;
  889. this._length = text.length;
  890. this._line = 1;
  891. this._stack = [];
  892. this._delimiter = null;
  893. }
  894. get file() {
  895. return this._file;
  896. }
  897. get line() {
  898. return this._line;
  899. }
  900. next() {
  901. if (this._stack.length > 0) {
  902. return this._stack.shift();
  903. }
  904. if (this._delimiter) {
  905. return this._readString();
  906. }
  907. let repeat;
  908. let prev;
  909. let curr;
  910. do {
  911. if (this._position === this._length) {
  912. return null;
  913. }
  914. repeat = false;
  915. while (/\s/.test(curr = this._get(this._position))) {
  916. if (curr === '\n') {
  917. this._line++;
  918. }
  919. this._position++;
  920. if (this._position === this._length) {
  921. return null;
  922. }
  923. }
  924. if (this._get(this._position) === '/') {
  925. this._position++;
  926. if (this._position === this._length) {
  927. throw this._readError('Invalid comment');
  928. }
  929. if (this._get(this._position) === '/') {
  930. while (this._get(++this._position) !== '\n') {
  931. if (this._position === this._length) {
  932. return null;
  933. }
  934. }
  935. this._position++;
  936. this._line++;
  937. repeat = true;
  938. }
  939. else if ((curr = this._get(this._position)) === '*') {
  940. do {
  941. if (curr === '\n') {
  942. this._line++;
  943. }
  944. this._position++;
  945. if (this._position === this._length) {
  946. throw this._readError('Invalid comment');
  947. }
  948. prev = curr;
  949. curr = this._get(this._position);
  950. } while (prev !== '*' || curr !== '/');
  951. this._position++;
  952. repeat = true;
  953. }
  954. else {
  955. return '/';
  956. }
  957. }
  958. }
  959. while (repeat);
  960. let end = this._position;
  961. const delimRe = /[\s{}=;:[\],'"()<>]/g;
  962. delimRe.lastIndex = 0;
  963. const delim = delimRe.test(this._get(end++));
  964. if (!delim) {
  965. while (end < this._length && !delimRe.test(this._get(end))) {
  966. end++;
  967. }
  968. }
  969. const position = this._position;
  970. this._position = end;
  971. const token = this._text.substring(position, this._position);
  972. if (token === '"' || token === "'") {
  973. this._delimiter = token;
  974. }
  975. return token;
  976. }
  977. peek() {
  978. if (!this._stack.length) {
  979. const token = this.next();
  980. if (token === null) {
  981. return null;
  982. }
  983. this.push(token);
  984. }
  985. return this._stack[0];
  986. }
  987. push(value) {
  988. this._stack.push(value);
  989. }
  990. expect(value) {
  991. const token = this.peek();
  992. if (token !== value) {
  993. throw this._readError("Unexpected '" + token + "' instead of '" + value + "'");
  994. }
  995. this.next();
  996. }
  997. eat(value) {
  998. const token = this.peek();
  999. if (token === value) {
  1000. this.next();
  1001. return true;
  1002. }
  1003. return false;
  1004. }
  1005. _get(pos) {
  1006. return this._text.charAt(pos);
  1007. }
  1008. static _unescape(str) {
  1009. return str.replace(/\\(.?)/g, function($0, $1) {
  1010. switch ($1) {
  1011. case '\\':
  1012. case '':
  1013. return $1;
  1014. case '0':
  1015. return '\0';
  1016. case 'r':
  1017. return '\r';
  1018. case 'n':
  1019. return '\n';
  1020. case 't':
  1021. return '\t';
  1022. default:
  1023. return '';
  1024. }
  1025. });
  1026. }
  1027. _readString() {
  1028. const re = this._delimiter === "'" ? /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g : /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g;
  1029. re.lastIndex = this._position - 1;
  1030. const match = re.exec(this._text);
  1031. if (!match) {
  1032. throw this._readError('Invalid string');
  1033. }
  1034. this._position = re.lastIndex;
  1035. this.push(this._delimiter);
  1036. this._delimiter = null;
  1037. return protoc.Parser.Tokenizer._unescape(match[1]);
  1038. }
  1039. _readError(message) {
  1040. const location = ' at ' + this._file + ':' + this._line.toString();
  1041. return new protoc.Error(message + location + '.');
  1042. }
  1043. location() {
  1044. return ' at ' + this.file + ':' + this.line;
  1045. }
  1046. };
  1047. protoc.Generator = class {
  1048. constructor(root, text) {
  1049. this._root = root;
  1050. this._text = text;
  1051. this._builder = new protoc.Generator.StringBuilder();
  1052. this._builder.add("var $root = protobuf.get('" + this._root.alias + "');");
  1053. this._buildContent(this._root);
  1054. this._content = this._builder.toString();
  1055. }
  1056. get content() {
  1057. return this._content;
  1058. }
  1059. _buildContent(namespace) {
  1060. for (const child of namespace.children.values()) {
  1061. this._builder.add('');
  1062. if (child instanceof protoc.Enum) {
  1063. this._buildEnum(child);
  1064. }
  1065. else if (child instanceof protoc.Type) {
  1066. this._buildType(child);
  1067. }
  1068. else {
  1069. this._buildNamespace(child);
  1070. }
  1071. }
  1072. }
  1073. _buildNamespace(namespace) {
  1074. const name = namespace.fullName.split('.').map((name) => protoc.Generator._escapeName(name)).join('.');
  1075. this._builder.add(name + ' = {};');
  1076. this._buildContent(namespace);
  1077. }
  1078. _buildEnum(type) {
  1079. /* eslint-disable indent */
  1080. const name = type.fullName.split('.').map((name) => protoc.Generator._escapeName(name)).join('.');
  1081. this._builder.add(name + ' = {');
  1082. this._builder.indent();
  1083. const keys = Object.keys(type.values);
  1084. for (let i = 0; i < keys.length; i++) {
  1085. const key = keys[i];
  1086. const value = type.values[key];
  1087. this._builder.add(JSON.stringify(key) + ': ' + value + ((i === keys.length - 1) ? '' : ','));
  1088. }
  1089. this._builder.outdent();
  1090. this._builder.add("};");
  1091. /* eslint-enable indent */
  1092. }
  1093. _buildType(type) {
  1094. const name = type.fullName.split('.').map((name) => protoc.Generator._escapeName(name)).join('.');
  1095. this._builder.add(name + ' = class ' + protoc.Generator._escapeName(type.name) + ' {');
  1096. this._builder.add('');
  1097. this._builder.indent();
  1098. this._buildConstructor(type);
  1099. for (const oneof of type.oneofs.values()) {
  1100. /* eslint-disable indent */
  1101. this._builder.add('');
  1102. this._builder.add('get ' + oneof.name + '() {');
  1103. this._builder.indent();
  1104. this._builder.add(name + '.' + oneof.name + 'Set = ' + name + '.' + oneof.name + 'Set || new Set([ ' + Array.from(oneof.oneof.keys()).map(JSON.stringify).join(', ') + ']);');
  1105. this._builder.add('return Object.keys(this).find((key) => ' + name + '.' + oneof.name + 'Set.has(key) && this[key] != null);');
  1106. this._builder.outdent();
  1107. this._builder.add('}');
  1108. /* eslint-enable indent */
  1109. }
  1110. this._builder.add('');
  1111. this._buildDecodeFunction(type);
  1112. if (this._text) {
  1113. this._builder.add('');
  1114. this._buildDecodeTextFunction(type);
  1115. }
  1116. this._builder.outdent();
  1117. this._builder.add('};');
  1118. let first = true;
  1119. for (const field of type.fields.values()) {
  1120. if (field.partOf || field.repeated || field instanceof protoc.MapField) {
  1121. continue;
  1122. }
  1123. if (first) {
  1124. this._builder.add('');
  1125. first = false;
  1126. }
  1127. if (field.type.long) {
  1128. if (field.type.name === 'uint64' || field.type.name === 'fixed64') {
  1129. this._builder.add(name + '.prototype' + protoc.Generator._propertyReference(field.name) + ' = protobuf.Uint64.create(' + field.defaultValue + ');');
  1130. }
  1131. else {
  1132. this._builder.add(name + '.prototype' + protoc.Generator._propertyReference(field.name) + ' = protobuf.Int64.create(' + field.defaultValue + ');');
  1133. }
  1134. }
  1135. else if (field.type.name === 'bytes') {
  1136. this._builder.add(name + '.prototype' + protoc.Generator._propertyReference(field.name) + ' = new Uint8Array(' + JSON.stringify(Array.prototype.slice.call(field.defaultValue)) + ");");
  1137. }
  1138. else {
  1139. this._builder.add(name + '.prototype' + protoc.Generator._propertyReference(field.name) + ' = ' + JSON.stringify(field.defaultValue) + ';');
  1140. }
  1141. }
  1142. this._buildContent(type);
  1143. }
  1144. _buildConstructor(type) {
  1145. /* eslint-disable indent */
  1146. this._builder.add('constructor() {');
  1147. this._builder.indent();
  1148. for (const field of type.fields.values()) {
  1149. if (field instanceof protoc.MapField) {
  1150. this._builder.add('this' + protoc.Generator._propertyReference(field.name) + ' = {};');
  1151. }
  1152. else if (field.repeated) {
  1153. this._builder.add('this' + protoc.Generator._propertyReference(field.name) + ' = [];');
  1154. }
  1155. }
  1156. this._builder.outdent();
  1157. this._builder.add('}');
  1158. /* eslint-enable indent */
  1159. }
  1160. _buildDecodeFunction(type) {
  1161. /* eslint-disable indent */
  1162. const fieldTypeName = (field) => "$root" + field.type.fullName;
  1163. this._builder.add('static decode(reader, length) {');
  1164. this._builder.indent();
  1165. this._builder.add('const message = new $root' + type.fullName + '();');
  1166. this._builder.add('const end = length !== undefined ? reader.position + length : reader.length;');
  1167. this._builder.add("while (reader.position < end) {");
  1168. this._builder.indent();
  1169. this._builder.add("const tag = reader.uint32();");
  1170. if (type.group) {
  1171. this._builder.add("if ((tag&7) === 4)");
  1172. this._builder.indent();
  1173. this._builder.add("break;");
  1174. this._builder.outdent();
  1175. }
  1176. this._builder.add("switch (tag >>> 3) {");
  1177. this._builder.indent();
  1178. for (const field of type.fields.values()) {
  1179. const variable = "message" + protoc.Generator._propertyReference(field.name);
  1180. this._builder.add('case ' + field.id + ':');
  1181. this._builder.indent();
  1182. if (field instanceof protoc.MapField) {
  1183. const value = field.type instanceof protoc.PrimitiveType ?
  1184. 'reader.' + field.type.name + '()' :
  1185. fieldTypeName(field) + '.decode(reader, reader.uint32())';
  1186. this._builder.add('reader.entry(' + variable + ', () => reader.' + field.keyType.name + '(), () => ' + value + ');');
  1187. }
  1188. else if (field.repeated) {
  1189. if (field.type.name === 'float' || field.type.name === 'double') {
  1190. this._builder.add(variable + ' = reader.' + field.type.name + 's(' + variable + ', tag);');
  1191. }
  1192. else if (field.type instanceof protoc.Enum) {
  1193. this._builder.add(variable + ' = reader.array(' + variable + ', () => reader.int32(), tag);');
  1194. }
  1195. else if (field.type instanceof protoc.PrimitiveType && field.type.packed) {
  1196. this._builder.add(variable + ' = reader.array(' + variable + ', () => reader.' + field.type.name + '(), tag);');
  1197. }
  1198. else if (field.type instanceof protoc.PrimitiveType) {
  1199. this._builder.add(variable + '.push(reader.' + field.type.name + '());');
  1200. }
  1201. else if (field.type.group) {
  1202. this._builder.add(variable + '.push(' + fieldTypeName(field) + '.decode(reader));');
  1203. }
  1204. else {
  1205. this._builder.add(variable + '.push(' + fieldTypeName(field) + '.decode(reader, reader.uint32()));');
  1206. }
  1207. }
  1208. else if (field.type instanceof protoc.Enum) {
  1209. this._builder.add(variable + ' = reader.int32();');
  1210. }
  1211. else if (field.type instanceof protoc.PrimitiveType) {
  1212. this._builder.add(variable + ' = reader.' + field.type.name + '();');
  1213. }
  1214. else if (field.type.group) {
  1215. this._builder.add(variable + ' = ' + fieldTypeName(field) + '.decode(reader);');
  1216. }
  1217. else {
  1218. this._builder.add(variable + ' = ' + fieldTypeName(field) + '.decode(reader, reader.uint32());');
  1219. }
  1220. this._builder.add('break;');
  1221. this._builder.outdent();
  1222. }
  1223. this._builder.add('default:');
  1224. this._builder.indent();
  1225. this._builder.add("reader.skipType(tag & 7);");
  1226. this._builder.add("break;");
  1227. this._builder.outdent();
  1228. this._builder.outdent();
  1229. this._builder.add("}");
  1230. this._builder.outdent();
  1231. this._builder.add('}');
  1232. for (const field of Array.from(type.fields.values()).filter((field) => field.required)) {
  1233. this._builder.add("if (!Object.prototype.hasOwnProperty.call(message, '" + field.name + "')) {");
  1234. this._builder.indent();
  1235. this._builder.add('throw new protobuf.Error("Excepted \'' + field.name + '\'.");');
  1236. this._builder.outdent();
  1237. this._builder.add('}');
  1238. }
  1239. this._builder.add('return message;');
  1240. this._builder.outdent();
  1241. this._builder.add('}');
  1242. /* eslint-enable indent */
  1243. }
  1244. _buildDecodeTextFunction(type) {
  1245. /* eslint-disable indent */
  1246. const typeName = (type) => "$root" + type.fullName;
  1247. this._builder.add('static decodeText(reader) {');
  1248. this._builder.indent();
  1249. if (type.fullName === '.google.protobuf.Any') {
  1250. this._builder.add('return reader.any(() => new ' + typeName(type) + '());');
  1251. }
  1252. else {
  1253. this._builder.add('const message = new ' + typeName(type) + '();');
  1254. this._builder.add('reader.start();');
  1255. this._builder.add('while (!reader.end()) {');
  1256. this._builder.indent();
  1257. this._builder.add('const tag = reader.tag();');
  1258. this._builder.add('switch (tag) {');
  1259. this._builder.indent();
  1260. for (const field of type.fields.values()) {
  1261. const variable = "message" + protoc.Generator._propertyReference(field.name);
  1262. this._builder.add('case "' + field.name + '":');
  1263. this._builder.indent();
  1264. // Map fields
  1265. if (field instanceof protoc.MapField) {
  1266. const value = field.type instanceof protoc.PrimitiveType ?
  1267. 'reader.' + field.type.name + '()' :
  1268. typeName(field.type) + '.decodeText(reader)';
  1269. this._builder.add('reader.entry(' + variable + ', () => reader.' + field.keyType.name + '(), () => ' + value + ');');
  1270. }
  1271. else if (field.repeated) { // Repeated fields
  1272. if (field.type instanceof protoc.Enum) {
  1273. this._builder.add('reader.array(' + variable + ', () => reader.enum(' + typeName(field.type) + '));');
  1274. }
  1275. else if (field.type instanceof protoc.PrimitiveType) {
  1276. this._builder.add('reader.array(' + variable + ', () => reader.' + field.type.name + '());');
  1277. }
  1278. else if (field.type.fullName === '.google.protobuf.Any') {
  1279. this._builder.add('reader.anyarray(' + variable + ', () => new ' + typeName(field.type) + '());');
  1280. }
  1281. else {
  1282. this._builder.add(variable + '.push(' + typeName(field.type) + '.decodeText(reader));');
  1283. }
  1284. // Non-repeated
  1285. }
  1286. else if (field.type instanceof protoc.Enum) {
  1287. this._builder.add(variable + ' = reader.enum(' + typeName(field.type) + ');');
  1288. }
  1289. else if (field.type instanceof protoc.PrimitiveType) {
  1290. this._builder.add(variable + ' = reader.' + field.type.name + '();');
  1291. }
  1292. else {
  1293. this._builder.add(variable + ' = ' + typeName(field.type) + '.decodeText(reader);');
  1294. }
  1295. this._builder.add("break;");
  1296. this._builder.outdent();
  1297. }
  1298. this._builder.add("default:");
  1299. this._builder.indent();
  1300. this._builder.add("reader.field(tag, message);");
  1301. this._builder.add("break;");
  1302. this._builder.outdent();
  1303. this._builder.outdent();
  1304. this._builder.add('}');
  1305. this._builder.outdent();
  1306. this._builder.add('}');
  1307. for (const field of Array.from(type.fields.values()).filter((field) => field.required)) {
  1308. this._builder.add('if (!Object.prototype.hasOwnProperty.call(message, "' + field.name + '")) {');
  1309. this._builder.indent();
  1310. this._builder.add('throw new protobuf.Error("Excepted \'' + field.name + '\'.");');
  1311. this._builder.outdent();
  1312. this._builder.add('}');
  1313. }
  1314. this._builder.add('return message;');
  1315. }
  1316. this._builder.outdent();
  1317. this._builder.add('}');
  1318. /* eslint-enable indent */
  1319. }
  1320. static _isKeyword(name) {
  1321. return /^(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/.test(name);
  1322. }
  1323. static _escapeName(name) {
  1324. return !name ? '$root' : protoc.Generator._isKeyword(name) ? name + '_' : name;
  1325. }
  1326. static _propertyReference(name) {
  1327. if (!/^[$\w_]+$/.test(name) || protoc.Generator._isKeyword(name)) {
  1328. return '["' + name.replace(/\\/g, '\\\\').replace(/"/g, "\\\"") + '"]';
  1329. }
  1330. return "." + name;
  1331. }
  1332. };
  1333. protoc.Generator.StringBuilder = class {
  1334. constructor() {
  1335. this._indentation = '';
  1336. this._lines = [];
  1337. this._newline = true;
  1338. }
  1339. indent() {
  1340. this._indentation += ' ';
  1341. }
  1342. outdent() {
  1343. if (this._indentation.length === 0) {
  1344. throw new protoc.Error('Invalid indentation.');
  1345. }
  1346. this._indentation = this._indentation.substring(0, this._indentation.length - 4);
  1347. }
  1348. add(text, newline) {
  1349. if (this._newline) {
  1350. if (text !== '') {
  1351. this._lines.push(this._indentation);
  1352. }
  1353. }
  1354. this._lines[this._lines.length - 1] = this._lines[this._lines.length - 1] + text + (newline === false ? '' : '\n');
  1355. this._newline = newline === false ? false : true;
  1356. }
  1357. toString() {
  1358. return this._lines.join('');
  1359. }
  1360. };
  1361. protoc.Error = class extends Error {
  1362. constructor(message) {
  1363. super(message);
  1364. this.name = 'Protocol Buffer Compiler Error';
  1365. }
  1366. };
  1367. const main = (args) => {
  1368. const options = { verbose: false, root: 'default', out: '', text: false, paths: [], files: [] };
  1369. while (args.length > 0) {
  1370. const arg = args.shift();
  1371. switch (arg) {
  1372. case '--verbose':
  1373. options.verbose = true;
  1374. break;
  1375. case '--out':
  1376. options.out = args.shift();
  1377. break;
  1378. case '--root':
  1379. options.root = args.shift();
  1380. break;
  1381. case '--text':
  1382. options.text = true;
  1383. break;
  1384. case '--path':
  1385. options.paths.push(args.shift());
  1386. break;
  1387. default:
  1388. if (arg.startsWith('-')) {
  1389. throw new protoc.Error("Invalid command line argument '" + arg + "'.");
  1390. }
  1391. options.files.push(arg);
  1392. break;
  1393. }
  1394. }
  1395. try {
  1396. const root = new protoc.Root(options.root, options.paths, options.files);
  1397. const generator = new protoc.Generator(root, options.text);
  1398. if (options.out) {
  1399. fs.writeFileSync(options.out, generator.content, 'utf-8');
  1400. }
  1401. }
  1402. catch (err) {
  1403. if (err instanceof protoc.Error && !options.verbose) {
  1404. process.stderr.write(err.message + '\n');
  1405. }
  1406. else {
  1407. process.stderr.write(err.stack + '\n');
  1408. }
  1409. return 1;
  1410. }
  1411. return 0;
  1412. };
  1413. if (typeof process === 'object' && Array.isArray(process.argv) &&
  1414. process.argv.length > 1 && process.argv[1] === __filename) {
  1415. const args = process.argv.slice(2);
  1416. const code = main(args);
  1417. process.exit(code);
  1418. }
  1419. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  1420. module.exports.Root = protoc.Root;
  1421. }