| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611 |
- import * as fs from 'fs/promises';
- import * as path from 'path';
- const protoc = {};
- protoc.Object = class {
- constructor(parent, name) {
- this.parent = parent;
- this.name = name;
- this.options = new Map();
- }
- get fullName() {
- const path = [this.name];
- let context = this.parent;
- while (context) {
- if (context.name) {
- path.unshift(context.name);
- }
- context = context.parent;
- }
- return path.join('.');
- }
- };
- protoc.Namespace = class extends protoc.Object {
- constructor(parent, name) {
- super(parent, name);
- this.children = new Map();
- if (!(this instanceof protoc.Root || this instanceof protoc.PrimitiveType)) {
- if (parent.get(this.name)) {
- throw new protoc.Error(`Duplicate name '${this.name}' in '${parent.name}'.`);
- }
- parent.children.set(this.name, this);
- }
- }
- defineNamespace(path) {
- path = path.split('.');
- if (path && path.length > 0 && path[0] === '') {
- throw new protoc.Error('Invalid path.');
- }
- /* eslint-disable consistent-this */
- let current = this;
- /* eslint-enable consistent-this */
- while (path.length > 0) {
- const part = path.shift();
- if (current.children && current.children.get(part)) {
- current = current.children.get(part);
- if (current instanceof protoc.Namespace === false) {
- throw new protoc.Error('Invalid path.');
- }
- } else {
- current = new protoc.Namespace(current, part);
- }
- }
- return current;
- }
- defineType(name) {
- const parts = name.split('.');
- const typeName = parts.pop();
- const parent = this.defineNamespace(parts.join('.'));
- const type = parent.get(name);
- if (type) {
- if (type instanceof protoc.Type) {
- return type;
- }
- throw new protoc.Error('Invalid type');
- }
- return new protoc.Type(parent, typeName);
- }
- get(name) {
- return this.children.get(name) || null;
- }
- find(path, filterType, parentAlreadyChecked) {
- if (path.length === 0) {
- return this;
- }
- if (path[0] === '') {
- return this.root.find(path.slice(1), filterType);
- }
- let found = this.get(path[0]);
- if (found) {
- if (path.length === 1) {
- if (found instanceof filterType) {
- return found;
- }
- } else if (found instanceof protoc.Namespace && (found = found.find(path.slice(1), filterType, true))) {
- return found;
- }
- } else {
- for (const child of this.children.values()) {
- if (child instanceof protoc.Namespace && (found = child.find(path, filterType, true))) {
- return found;
- }
- }
- }
- if (!this.parent || parentAlreadyChecked) {
- return null;
- }
- return this.parent.find(path, filterType);
- }
- findType(path) {
- const type = this.find(path.split('.'), protoc.Type);
- if (!type) {
- throw new protoc.Error(`Type or enum '${path}' not found in '${this.name}'.`);
- }
- return type;
- }
- static isReservedId(reserved, id) {
- if (reserved) {
- for (let i = 0; i < reserved.length; ++i) {
- if (typeof reserved[i] !== 'string' && reserved[i][0] <= id && reserved[i][1] > id) {
- return true;
- }
- }
- }
- return false;
- }
- static isReservedName(reserved, name) {
- if (reserved) {
- for (let i = 0; i < reserved.length; ++i) {
- if (reserved[i] === name) {
- return true;
- }
- }
- }
- return false;
- }
- };
- protoc.Root = class extends protoc.Namespace {
- constructor(alias) {
- super(null, '');
- this.alias = alias;
- this._files = new Set();
- this._library = new Map();
- this._library.set('google/protobuf/any.proto', () => {
- const type = this.defineType('google.protobuf.Any');
- type.defineField('type_url', 1, 'string');
- type.defineField('value', 2, 'bytes');
- });
- this._library.set('google/protobuf/wrappers.proto', () => {
- const type = this.defineType('google.protobuf.BoolValue');
- type.defineField('value', 1, 'bool');
- });
- }
- async load(paths, files) {
- for (const file of files) {
- /* eslint-disable no-await-in-loop */
- const resolved = await this._resolve(file, '', paths);
- /* eslint-enable no-await-in-loop */
- if (resolved) {
- /* eslint-disable no-await-in-loop */
- await this._loadFile(paths, resolved);
- /* eslint-enable no-await-in-loop */
- } else {
- throw new protoc.Error(`File '${file}' not found.`);
- }
- }
- return this;
- }
- async _loadFile(paths, file, weak) {
- if (!this._files.has(file)) {
- this._files.add(file);
- if (this._library.has(file)) {
- const callback = this._library.get(file);
- callback();
- } else {
- try {
- await this._parseFile(paths, file);
- } catch (error) {
- if (!weak) {
- throw error;
- }
- }
- }
- }
- }
- async _parseFile(paths, file) {
- const source = await fs.readFile(file, 'utf-8');
- const parser = new protoc.Parser(source, file, this);
- const parsed = parser.parse();
- for (const item of parsed.imports) {
- /* eslint-disable no-await-in-loop */
- const resolved = await this._resolve(item, file, paths);
- /* eslint-enable no-await-in-loop */
- if (!resolved) {
- throw new protoc.Error(`File '${item}' not found.`);
- }
- /* eslint-disable no-await-in-loop */
- await this._loadFile(paths, resolved);
- /* eslint-enable no-await-in-loop */
- }
- for (const item of parsed.weakImports) {
- /* eslint-disable no-await-in-loop */
- const resolved = await this._resolve(item, file, paths);
- /* eslint-enable no-await-in-loop */
- if (resolved) {
- /* eslint-disable no-await-in-loop */
- await this._loadFile(paths, resolved);
- /* eslint-enable no-await-in-loop */
- }
- }
- }
- async _resolve(target, source, paths) {
- const file = path.resolve(source, target);
- const posix = file.split(path.sep).join(path.posix.sep);
- const index = posix.lastIndexOf('google/protobuf/');
- if (index > -1) {
- const name = posix.substring(index);
- if (this._library.has(name)) {
- return name;
- }
- }
- const access = async (path) => {
- try {
- await fs.access(path);
- return true;
- } catch {
- return false;
- }
- };
- const exists = await access(file);
- if (exists) {
- return file;
- }
- for (const dir of paths) {
- const file = path.resolve(dir, target);
- /* eslint-disable no-await-in-loop */
- const exists = await access(file);
- if (exists) {
- return file;
- }
- /* eslint-enable no-await-in-loop */
- }
- return null;
- }
- };
- protoc.Type = class extends protoc.Namespace {
- constructor(parent, name) {
- super(parent, name);
- this.fields = new Map();
- this.oneofs = new Map();
- this.extensions = [];
- this.reserved = [];
- }
- get(name) {
- return this.fields.get(name) || this.oneofs.get(name) || this.children.get(name) || null;
- }
- defineField(name, id, type, rule, extend) {
- return new protoc.Field(this, name, id, type, rule, extend);
- }
- };
- protoc.Enum = class extends protoc.Type {
- constructor(parent, name) {
- super(parent, name);
- this.valuesById = new Map();
- this.values = {};
- this.reserved = [];
- }
- add(name, id) {
- if (!Number.isInteger(id)) {
- throw new protoc.Error('Identifier must be an integer.');
- }
- if (this.values[name] !== undefined) {
- throw new protoc.Error(`Duplicate name '${name}' in '${this.name}'.`);
- }
- if (protoc.Namespace.isReservedId(this.reserved, id)) {
- throw new protoc.Error(`Identifier '${id}' is reserved in '${this.name}'.`);
- }
- if (protoc.Namespace.isReservedName(this.reserved, name)) {
- throw new protoc.Error(`Name '${name}' is reserved in '${this.name}'.`);
- }
- if (this.valuesById.has(id)) {
- if (!this.options.has('allow_alias')) {
- throw new protoc.Error(`Duplicate identifier '${id}' in '${this.name}'.`);
- }
- } else {
- this.valuesById.set(id, name);
- }
- this.values[name] = id;
- }
- };
- protoc.PrimitiveType = class extends protoc.Type {
- constructor(name, long, mapKey, packed, defaultValue) {
- super(null, name);
- this.long = long;
- this.mapKey = mapKey;
- this.packed = packed;
- this.defaultValue = defaultValue;
- }
- static get(name) {
- if (!this._map) {
- this._map = new Map();
- const register = (type) => this._map.set(type.name, type);
- register(new protoc.PrimitiveType('double', false, false, true, 0));
- register(new protoc.PrimitiveType('float', false, false, true, 0));
- register(new protoc.PrimitiveType('int32', false, true, true, 0));
- register(new protoc.PrimitiveType('uint32', false, true, true, 0));
- register(new protoc.PrimitiveType('sint32', false, true, true, 0));
- register(new protoc.PrimitiveType('fixed32', false, true, true, 0));
- register(new protoc.PrimitiveType('sfixed32', false, true, true, 0));
- register(new protoc.PrimitiveType('int64', true, true, true, 0));
- register(new protoc.PrimitiveType('uint64', true, true, true, 0));
- register(new protoc.PrimitiveType('sint64', true, true, true, 0));
- register(new protoc.PrimitiveType('fixed64', true, true, true, 0));
- register(new protoc.PrimitiveType('sfixed64', true, true, true, 0));
- register(new protoc.PrimitiveType('bool', false, true, true, false));
- register(new protoc.PrimitiveType('string', false, true, false, ''));
- register(new protoc.PrimitiveType('bytes', false, true, false, []));
- }
- return this._map.get(name);
- }
- };
- protoc.Field = class extends protoc.Object {
- constructor(parent, name, id, type, rule, extend) {
- super(parent instanceof protoc.OneOf ? parent.parent : parent, name);
- if (!Number.isInteger(id) || id < 0) {
- throw new protoc.Error('Identifier must be a non-negative integer.');
- }
- if (rule && rule !== 'required' && rule !== 'optional' && rule !== 'repeated') {
- throw new protoc.Error('Rule must be a string.');
- }
- this.id = id;
- this._type = type;
- this.rule = rule && rule !== 'optional' ? rule : undefined;
- this.extend = extend;
- this.required = rule === 'required';
- this.repeated = rule === 'repeated';
- if (parent instanceof protoc.OneOf) {
- this.partOf = parent;
- parent.oneof.set(this.name, this);
- parent = parent.parent;
- }
- if (parent.get(this.name)) {
- throw new protoc.Error(`Duplicate name '${this.name}' in '${parent.name}'.`);
- }
- if (protoc.Namespace.isReservedId(parent.reserved, this.id)) {
- throw new protoc.Error(`Identifier '${this.id}' is reserved in '${parent.name}'.`);
- }
- if (protoc.Namespace.isReservedName(parent.reserved, this.name)) {
- throw new protoc.Error(`Name '${this.name}' is reserved in '${parent.name}'.`);
- }
- parent.fields.set(this.name, this);
- }
- get type() {
- if (typeof this._type === 'string') {
- this._type = protoc.PrimitiveType.get(this._type) || this.parent.findType(this._type);
- }
- return this._type;
- }
- get defaultValue() {
- const type = this.type;
- let value = null;
- if (type instanceof protoc.PrimitiveType) {
- value = type.defaultValue;
- } else if (type instanceof protoc.Enum) {
- value = type.values[Object.keys(type.values)[0]];
- }
- if (this.options.has('default')) {
- value = this.options.get('default');
- if (type instanceof protoc.Enum && typeof value === 'string') {
- value = type.values[value];
- }
- }
- if (type === 'bytes' && typeof value === 'string') {
- throw new protoc.Error('Unsupported bytes field.');
- }
- return value;
- }
- };
- protoc.OneOf = class extends protoc.Object {
- constructor(parent, name) {
- super(parent, name);
- this.oneof = new Map();
- if (parent.get(this.name)) {
- throw new protoc.Error(`Duplicate name '${this.name}' in '${parent.name}'.`);
- }
- parent.oneofs.set(this.name, this);
- }
- };
- protoc.MapField = class extends protoc.Field {
- constructor(parent, name, id, keyType, type) {
- super(parent, name, id, type);
- this.keyType = protoc.PrimitiveType.get(keyType);
- }
- };
- protoc.Parser = class {
- constructor(text, file, root) {
- this._context = root;
- this._tokenizer = new protoc.Tokenizer(text, file);
- this._head = true;
- this._imports = [];
- this._weakImports = [];
- }
- parse() {
- let token = '';
- while ((token = this._tokenizer.next()) !== null) {
- switch (token) {
- case 'package':
- if (!this._head) {
- throw this._parseError(token);
- }
- this._parsePackage();
- break;
- case 'import':
- if (!this._head) {
- throw this._parseError(token);
- }
- this._parseImport();
- break;
- case 'syntax':
- if (!this._head) {
- throw this._parseError(token);
- }
- this._parseSyntax();
- break;
- case 'option':
- this._parseOption(this._context, token);
- this._tokenizer.expect(';');
- break;
- default:
- if (this._parseCommon(this._context, token)) {
- this._head = false;
- continue;
- }
- throw this._parseError(token);
- }
- }
- return { package: this._package, imports: this._imports, weakImports: this._weakImports };
- }
- _parseId(token, acceptNegative) {
- switch (token) {
- case 'max':
- case 'Max':
- case 'MAX':
- return 0x1fffffff;
- case '0':
- return 0;
- default: {
- if (!acceptNegative && token.charAt(0) === "-") {
- throw this._parseError(token, 'id');
- }
- if (/^-?[1-9][0-9]*$/.test(token)) {
- return parseInt(token, 10);
- }
- if (/^-?0[x][0-9a-fA-F]+$/.test(token)) {
- return parseInt(token, 16);
- }
- if (/^-?0[0-7]+$/.test(token)) {
- return parseInt(token, 8);
- }
- throw this._parseError(token, 'id');
- }
- }
- }
- _parsePackage() {
- if (this._package) {
- throw this._parseError("package");
- }
- this._package = this._tokenizer.next();
- if (!protoc.Parser._isTypeReference(this._package)) {
- throw this._parseError(this._package, 'name');
- }
- this._context = this._context.defineNamespace(this._package);
- this._tokenizer.expect(";");
- }
- _parseImport() {
- let token = this._tokenizer.peek();
- if (token === 'weak') {
- this._tokenizer.next();
- token = this._readString();
- this._tokenizer.expect(";");
- this._weakImports.push(token);
- } else {
- if (token === 'public') {
- this._tokenizer.next();
- }
- token = this._readString();
- this._tokenizer.expect(";");
- this._imports.push(token);
- }
- }
- _parseSyntax() {
- this._tokenizer.expect("=");
- this._syntax = this._readString();
- if (this._syntax !== 'proto2' && this._syntax !== 'proto3') {
- throw this._parseError(this._syntax, 'syntax');
- }
- this._tokenizer.expect(";");
- }
- _parseCommon(parent, token) {
- switch (token) {
- case 'option':
- this._parseOption(parent, token);
- this._tokenizer.expect(";");
- return true;
- case 'message':
- this._parseType(parent, token);
- return true;
- case 'enum':
- this._parseEnum(parent, token);
- return true;
- case 'extend':
- this._parseExtend(parent, token);
- return true;
- case 'service':
- throw new protoc.Error(`Keyword '${token}' is not supported ${this._tokenizer.location()}`);
- default:
- return false;
- }
- }
- _ifBlock(obj, ifCallback, elseCallback) {
- if (obj) {
- obj.file = this._file;
- }
- if (this._tokenizer.accept("{")) {
- let token = '';
- while ((token = this._tokenizer.next()) !== "}") {
- ifCallback(token);
- }
- this._tokenizer.accept(";");
- } else {
- if (elseCallback) {
- elseCallback();
- }
- this._tokenizer.expect(";");
- }
- }
- _parseType(parent, token) {
- token = this._tokenizer.next();
- if (!protoc.Parser._isName(token)) {
- throw this._parseError(token, 'type');
- }
- const type = new protoc.Type(parent, token);
- this._ifBlock(type, (token) => {
- if (this._parseCommon(type, token)) {
- return;
- }
- switch (token) {
- case 'map':
- this._parseMapField(type, token);
- break;
- case 'required':
- case 'optional':
- case 'repeated':
- this._parseField(type, token);
- break;
- case 'oneof':
- this._parseOneOf(type, token);
- break;
- case 'reserved':
- this._readRanges(type.reserved, true);
- break;
- case 'extensions':
- this._readRanges(type.extensions);
- break;
- default:
- if (this._syntax !== 'proto3' || !protoc.Parser._isTypeReference(token)) {
- throw this._parseError(token);
- }
- this._tokenizer.push(token);
- this._parseField(type, 'optional');
- break;
- }
- });
- }
- _parseField(parent, rule, extend) {
- const type = this._tokenizer.next();
- if (type === "group") {
- this._parseGroup(parent, rule);
- return;
- }
- if (!protoc.Parser._isTypeReference(type)) {
- throw this._parseError(type, 'type');
- }
- const name = this._tokenizer.next();
- if (!protoc.Parser._isName(name)) {
- throw this._parseError(name, 'name');
- }
- this._tokenizer.expect("=");
- const id = this._parseId(this._tokenizer.next());
- const field = new protoc.Field(parent, name, id, type, rule, extend);
- this._ifBlock(field, (token) => {
- if (token === "option") {
- this._parseOption(field, token);
- this._tokenizer.expect(";");
- } else {
- throw this._parseError(token);
- }
- }, () => {
- this._parseInlineOptions(field);
- });
- }
- _parseGroup(parent, rule) {
- let name = this._tokenizer.next();
- if (!protoc.Parser._isName(name)) {
- throw this._parseError(name, 'name');
- }
- const fieldName = name.charAt(0).toLowerCase() + name.substring(1);
- if (name === fieldName) {
- name = name.charAt(0).toUpperCase() + name.substring(1);
- }
- this._tokenizer.expect("=");
- const id = this._parseId(this._tokenizer.next());
- const type = new protoc.Type(name);
- type.group = true;
- const field = new protoc.Field(parent, fieldName, id, name, rule);
- field.file = this._file;
- this._ifBlock(type, (token) => {
- switch (token) {
- case "option":
- this._parseOption(type, token);
- this._tokenizer.expect(";");
- break;
- case "required":
- case "optional":
- case "repeated":
- this._parseField(type, token);
- break;
- default:
- throw this._parseError(token); // there are no groups with proto3 semantics
- }
- });
- parent.add(type).add(field);
- }
- _parseMapField(parent) {
- this._tokenizer.expect("<");
- const keyType = this._tokenizer.next();
- const resolvedKeyType = protoc.PrimitiveType.get(keyType);
- if (!resolvedKeyType || !resolvedKeyType.mapKey) {
- throw this._parseError(keyType, 'type');
- }
- this._tokenizer.expect(",");
- const valueType = this._tokenizer.next();
- if (!protoc.Parser._isTypeReference(valueType)) {
- throw this._parseError(valueType, 'type');
- }
- this._tokenizer.expect(">");
- const name = this._tokenizer.next();
- if (!protoc.Parser._isName(name)) {
- throw this._parseError(name, 'name');
- }
- this._tokenizer.expect("=");
- const id = this._parseId(this._tokenizer.next());
- const field = new protoc.MapField(parent, name, id, keyType, valueType);
- this._ifBlock(field, (token) => {
- if (token === "option") {
- this._parseOption(field, token);
- this._tokenizer.expect(";");
- } else {
- throw this._parseError(token);
- }
- }, () => {
- this._parseInlineOptions(field);
- });
- }
- _parseOneOf(parent, token) {
- token = this._tokenizer.next();
- if (!protoc.Parser._isName(token)) {
- throw this._parseError(token, 'name');
- }
- const oneof = new protoc.OneOf(parent, token);
- this._ifBlock(oneof, (token) => {
- if (token === "option") {
- this._parseOption(oneof, token);
- this._tokenizer.expect(";");
- } else {
- this._tokenizer.push(token);
- this._parseField(oneof, 'optional');
- }
- });
- }
- _parseEnum(parent, token) {
- token = this._tokenizer.next();
- if (!protoc.Parser._isName(token)) {
- throw this._parseError(token, 'name');
- }
- const obj = new protoc.Enum(parent, token);
- this._ifBlock(obj, (token) => {
- switch (token) {
- case "option":
- this._parseOption(obj, token);
- this._tokenizer.expect(";");
- break;
- case "reserved":
- this._readRanges(obj.reserved, true);
- break;
- default:
- this._parseEnumValue(obj, token);
- break;
- }
- });
- }
- _parseEnumValue(parent, token) {
- if (!protoc.Parser._isName(token)) {
- throw this._parseError(token, 'name');
- }
- this._tokenizer.expect("=");
- const value = this._parseId(this._tokenizer.next(), true);
- const dummy = {};
- this._ifBlock(dummy, (token) => {
- if (token === "option") {
- this._parseOption(dummy, token); // skip
- this._tokenizer.expect(";");
- } else {
- throw this._parseError(token);
- }
- }, () => {
- this._parseInlineOptions(dummy); // skip
- });
- parent.add(token, value);
- }
- _parseExtend(parent, token) {
- token = this._tokenizer.next();
- if (!protoc.Parser._isTypeReference(token)) {
- throw this._parseError(token, 'reference');
- }
- const reference = token;
- this._ifBlock(null, (token) => {
- switch (token) {
- case "required":
- case "repeated":
- case "optional":
- this._parseField(parent, token, reference);
- break;
- default:
- if (this._syntax === 'proto3' || !protoc.Parser._isTypeReference(token)) {
- throw this._parseError(token);
- }
- this._tokenizer.push(token);
- this._parseField(parent, 'optional', reference);
- break;
- }
- });
- }
- _parseOption(parent, token) {
- const custom = this._tokenizer.accept("(");
- token = this._tokenizer.next();
- if (!protoc.Parser._isTypeReference(token)) {
- throw this._parseError(token, 'name');
- }
- let name = token;
- if (custom) {
- this._tokenizer.expect(")");
- name = `(${name})`;
- token = this._tokenizer.peek();
- if (/^(?:\.[a-zA-Z_][a-zA-Z_0-9]*)+$/.test(token)) {
- name += token;
- this._tokenizer.next();
- }
- }
- this._tokenizer.expect("=");
- this._parseOptionValue(parent, name);
- }
- _parseOptionValue(parent, name) {
- if (this._tokenizer.accept('{')) {
- while (!this._tokenizer.accept('}')) {
- const token = this._tokenizer.next();
- if (!protoc.Parser._isName(token)) {
- throw this._parseError(token, 'name');
- }
- if (this._tokenizer.peek() === '{') {
- this._parseOptionValue(parent, `${name}.${token}`);
- } else {
- this._tokenizer.expect(':');
- if (this._tokenizer.peek() === '{') {
- this._parseOptionValue(parent, `${name}.${token}`);
- } else {
- parent.options.set(`${name}.${token}`, this._readValue());
- }
- }
- this._tokenizer.accept(',');
- }
- } else {
- parent.options.set(name, this._readValue());
- }
- }
- _parseInlineOptions(parent) {
- if (this._tokenizer.accept('[')) {
- do {
- this._parseOption(parent, 'option');
- }
- while (this._tokenizer.accept(','));
- this._tokenizer.expect(']');
- }
- return parent;
- }
- _readString() {
- const values = [];
- let token = '';
- do {
- if ((token = this._tokenizer.next()) !== '"' && token !== "'") {
- throw this._parseError(token);
- }
- values.push(this._tokenizer.next());
- this._tokenizer.expect(token);
- token = this._tokenizer.peek();
- }
- while (token === '"' || token === "'");
- return values.join('');
- }
- _readValue() {
- const token = this._tokenizer.next();
- switch (token) {
- case "'":
- case '"':
- this._tokenizer.push(token);
- return this._readString();
- case 'true':
- case 'TRUE':
- return true;
- case 'false':
- case 'FALSE':
- return false;
- default: {
- const value = this._parseNumber(token);
- if (value !== undefined) {
- return value;
- }
- if (protoc.Parser._isTypeReference(token)) {
- return token;
- }
- throw this._parseError(token, 'value');
- }
- }
- }
- _readRanges(target, acceptStrings) {
- do {
- let token = '';
- if (acceptStrings && ((token = this._tokenizer.peek()) === '"' || token === "'")) {
- target.push(this._readString());
- } else {
- const start = this._parseId(this._tokenizer.next());
- const end = this._tokenizer.accept('to') ? this._parseId(this._tokenizer.next()) : start;
- target.push([start, end]);
- }
- }
- while (this._tokenizer.accept(','));
- this._tokenizer.expect(';');
- }
- _parseNumber(token) {
- let sign = 1;
- if (token.charAt(0) === '-') {
- sign = -1;
- token = token.substring(1);
- }
- switch (token) {
- case 'inf':
- case 'INF':
- case 'Inf': {
- return sign * Infinity;
- }
- case 'nan':
- case 'NAN':
- case 'Nan':
- case 'NaN': {
- return NaN;
- }
- case '0': {
- return 0;
- }
- default: {
- if (/^[1-9][0-9]*$/.test(token)) {
- return sign * parseInt(token, 10);
- }
- if (/^0[x][0-9a-fA-F]+$/.test(token)) {
- return sign * parseInt(token, 16);
- }
- if (/^0[0-7]+$/.test(token)) {
- return sign * parseInt(token, 8);
- }
- if (/^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/.test(token)) {
- return sign * parseFloat(token);
- }
- return undefined;
- }
- }
- }
- static _isName(value) {
- return /^[a-zA-Z_][a-zA-Z_0-9]*$/.test(value);
- }
- static _isTypeReference(value) {
- return /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/.test(value);
- }
- _parseError(token, name) {
- name = name || 'token';
- const location = this._tokenizer.location();
- return new protoc.Error(`Invalid ${name} '${token}' ${location}.`);
- }
- };
- protoc.Tokenizer = class {
- constructor(text, file) {
- this._text = text;
- this._file = file;
- this._position = 0;
- this._length = text.length;
- this._line = 1;
- this._stack = [];
- this._delimiter = null;
- }
- get file() {
- return this._file;
- }
- get line() {
- return this._line;
- }
- next() {
- if (this._stack.length > 0) {
- return this._stack.shift();
- }
- if (this._delimiter) {
- return this._readString();
- }
- let repeat = false;
- let prev = '';
- let curr = '';
- do {
- if (this._position === this._length) {
- return null;
- }
- repeat = false;
- while (/\s/.test(curr = this._get(this._position))) {
- if (curr === '\n') {
- this._line++;
- }
- this._position++;
- if (this._position === this._length) {
- return null;
- }
- }
- if (this._get(this._position) === '/') {
- this._position++;
- if (this._position === this._length) {
- throw this._readError('Invalid comment');
- }
- if (this._get(this._position) === '/') {
- while (this._get(++this._position) !== '\n') {
- if (this._position === this._length) {
- return null;
- }
- }
- this._position++;
- this._line++;
- repeat = true;
- } else if ((curr = this._get(this._position)) === '*') {
- do {
- if (curr === '\n') {
- this._line++;
- }
- this._position++;
- if (this._position === this._length) {
- throw this._readError('Invalid comment');
- }
- prev = curr;
- curr = this._get(this._position);
- } while (prev !== '*' || curr !== '/');
- this._position++;
- repeat = true;
- } else {
- return '/';
- }
- }
- }
- while (repeat);
- let end = this._position;
- const delimRe = /[\s{}=;:[\],'"()<>]/g;
- delimRe.lastIndex = 0;
- const delim = delimRe.test(this._get(end++));
- if (!delim) {
- while (end < this._length && !delimRe.test(this._get(end))) {
- end++;
- }
- }
- const position = this._position;
- this._position = end;
- const token = this._text.substring(position, this._position);
- if (token === '"' || token === "'") {
- this._delimiter = token;
- }
- return token;
- }
- peek() {
- if (!this._stack.length) {
- const token = this.next();
- if (token === null) {
- return null;
- }
- this.push(token);
- }
- return this._stack[0];
- }
- push(value) {
- this._stack.push(value);
- }
- expect(value) {
- const token = this.peek();
- if (token !== value) {
- throw this._readError(`Unexpected '${token}' instead of '${value}'`);
- }
- this.next();
- }
- accept(value) {
- const token = this.peek();
- if (token === value) {
- this.next();
- return true;
- }
- return false;
- }
- _get(pos) {
- return this._text.charAt(pos);
- }
- static _unescape(str) {
- return str.replace(/\\(.?)/g, ($0, $1) => {
- switch ($1) {
- case '\\':
- case '':
- return $1;
- case '0':
- return '\0';
- case 'r':
- return '\r';
- case 'n':
- return '\n';
- case 't':
- return '\t';
- default:
- return '';
- }
- });
- }
- _readString() {
- const re = this._delimiter === "'" ? /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g : /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g;
- re.lastIndex = this._position - 1;
- const match = re.exec(this._text);
- if (!match) {
- throw this._readError('Invalid string');
- }
- this._position = re.lastIndex;
- this.push(this._delimiter);
- this._delimiter = null;
- return protoc.Tokenizer._unescape(match[1]);
- }
- _readError(message) {
- const location = `at ${this._file}:${this._line}.`;
- return new protoc.Error(`${message} ${location}`);
- }
- location() {
- return `at ${this.file}:${this.line}.`;
- }
- };
- protoc.Generator = class {
- constructor(root, options) {
- this._root = root;
- this._options = options;
- this._builder = new protoc.Generator.StringBuilder();
- const scopes = Array.from(this._root.children.values()).map((child) => child.fullName);
- const exports = new Set(scopes.map((scope) => scope.split('.')[0]));
- this._builder.add('');
- for (const value of exports) {
- this._builder.add(`export const ${value} = {};`);
- }
- this._buildContent(this._root);
- this._content = this._builder.toString();
- }
- get content() {
- return this._content;
- }
- _buildContent(namespace) {
- for (const child of namespace.children.values()) {
- if (child instanceof protoc.Enum) {
- this._builder.add('');
- this._buildEnum(child);
- } else if (child instanceof protoc.Type) {
- this._builder.add('');
- this._buildType(child);
- } else if (child instanceof protoc.Namespace) {
- const name = child.fullName.split('.').map((name) => protoc.Generator._escapeName(name)).join('.');
- if (name.indexOf('.') !== -1) {
- this._builder.add('');
- this._builder.add(`${name} = {};`);
- }
- this._buildContent(child);
- } else {
- throw new protoc.Error('Unsupportd namespace child.');
- }
- }
- }
- _buildEnum(type) {
- /* eslint-disable indent */
- const name = type.fullName.split('.').map((name) => protoc.Generator._escapeName(name)).join('.');
- this._builder.add(`${name} = {`);
- this._builder.indent();
- const keys = Object.keys(type.values);
- for (let i = 0; i < keys.length; i++) {
- const key = keys[i];
- const value = type.values[key];
- this._builder.add(`${JSON.stringify(key)}: ${value}${(i === keys.length - 1) ? '' : ','}`);
- }
- this._builder.outdent();
- this._builder.add("};");
- /* eslint-enable indent */
- }
- _buildType(type) {
- const name = type.fullName.split('.').map((name) => protoc.Generator._escapeName(name)).join('.');
- this._builder.add(`${name} = class ${protoc.Generator._escapeName(type.name)} {`);
- this._builder.indent();
- this._buildConstructor(type);
- for (const oneof of type.oneofs.values()) {
- /* eslint-disable indent */
- this._builder.add('');
- this._builder.add(`get ${oneof.name}() {`);
- this._builder.indent();
- this._builder.add(`${name}.${oneof.name}Set = ${name}.${oneof.name}Set || new Set([${Array.from(oneof.oneof.keys()).map(JSON.stringify).join(', ')}]);`);
- this._builder.add(`return Object.keys(this).find((key) => ${name}.${oneof.name}Set.has(key) && this[key] !== null);`);
- this._builder.outdent();
- this._builder.add('}');
- /* eslint-enable indent */
- }
- if (this._options.binary) {
- this._builder.add('');
- this._buildDecodeFunction(type);
- }
- if (this._options.text) {
- this._builder.add('');
- this._buildDecodeTextFunction(type);
- }
- if (this._options.json) {
- this._builder.add('');
- this._buildDecodeJsonFunction(type);
- }
- this._builder.outdent();
- this._builder.add('};');
- let first = true;
- for (const field of type.fields.values()) {
- if (field.partOf || field.repeated || field instanceof protoc.MapField) {
- continue;
- }
- if (first) {
- this._builder.add('');
- first = false;
- }
- if (field.type.long) {
- if (field.type.name === 'uint64' || field.type.name === 'fixed64') {
- this._builder.add(`${name}.prototype${protoc.Generator._propertyReference(field.name)} = ${field.defaultValue}n;`);
- } else {
- this._builder.add(`${name}.prototype${protoc.Generator._propertyReference(field.name)} = ${field.defaultValue}n;`);
- }
- } else if (field.type.name === 'bytes') {
- this._builder.add(`${name}.prototype${protoc.Generator._propertyReference(field.name)} = new Uint8Array(${JSON.stringify(Array.prototype.slice.call(field.defaultValue))});`);
- } else {
- this._builder.add(`${name}.prototype${protoc.Generator._propertyReference(field.name)} = ${JSON.stringify(field.defaultValue)};`);
- }
- }
- this._buildContent(type);
- }
- _buildConstructor(type) {
- const filter = (field) => field instanceof protoc.MapField || field.repeated;
- const fields = Array.from(type.fields.values()).filter(filter);
- if (fields.length === 0) {
- return;
- }
- /* eslint-disable indent */
- this._builder.add('');
- this._builder.add('constructor() {');
- this._builder.indent();
- for (const field of fields) {
- if (field instanceof protoc.MapField) {
- this._builder.add(`this${protoc.Generator._propertyReference(field.name)} = {};`);
- } else if (field.repeated) {
- this._builder.add(`this${protoc.Generator._propertyReference(field.name)} = [];`);
- }
- }
- this._builder.outdent();
- this._builder.add('}');
- /* eslint-enable indent */
- }
- _buildDecodeFunction(type) {
- /* eslint-disable indent */
- const fieldTypeName = (field) => `${field.type.fullName}`;
- this._builder.add('static decode(reader, length) {');
- this._builder.indent();
- this._builder.add(`const message = new ${type.fullName}();`);
- this._builder.add('const end = length === undefined ? reader.length : reader.position + length;');
- this._builder.add("while (reader.position < end) {");
- this._builder.indent();
- this._builder.add("const tag = reader.uint32();");
- if (type.group) {
- this._builder.add("if ((tag&7) === 4)");
- this._builder.indent();
- this._builder.add("break;");
- this._builder.outdent();
- }
- this._builder.add("switch (tag >>> 3) {");
- this._builder.indent();
- for (const field of type.fields.values()) {
- const variable = `message${protoc.Generator._propertyReference(field.name)}`;
- this._builder.add(`case ${field.id}:`);
- this._builder.indent();
- if (field instanceof protoc.MapField) {
- const value = field.type instanceof protoc.PrimitiveType ?
- `reader.${field.type.name}()` :
- `${fieldTypeName(field)}.decode(reader, reader.uint32())`;
- this._builder.add(`reader.entry(${variable}, () => reader.${field.keyType.name}(), () => ${value});`);
- } else if (field.repeated) {
- if (field.type.name === 'float' || field.type.name === 'double') {
- this._builder.add(`${variable} = reader.${field.type.name}s(${variable}, tag);`);
- } else if (field.type instanceof protoc.Enum) {
- this._builder.add(`${variable} = reader.array(${variable}, () => reader.int32(), tag);`);
- } else if (field.type instanceof protoc.PrimitiveType && field.type.packed) {
- this._builder.add(`${variable} = reader.array(${variable}, () => reader.${field.type.name}(), tag);`);
- } else if (field.type instanceof protoc.PrimitiveType) {
- this._builder.add(`${variable}.push(reader.${field.type.name}());`);
- } else if (field.type.group) {
- this._builder.add(`${variable}.push(${fieldTypeName(field)}.decode(reader));`);
- } else {
- this._builder.add(`${variable}.push(${fieldTypeName(field)}.decode(reader, reader.uint32()));`);
- }
- } else if (field.type instanceof protoc.Enum) {
- this._builder.add(`${variable} = reader.int32();`);
- } else if (field.type instanceof protoc.PrimitiveType) {
- this._builder.add(`${variable} = reader.${field.type.name}();`);
- } else if (field.type.group) {
- this._builder.add(`${variable} = ${fieldTypeName(field)}.decode(reader);`);
- } else {
- this._builder.add(`${variable} = ${fieldTypeName(field)}.decode(reader, reader.uint32());`);
- }
- this._builder.add('break;');
- this._builder.outdent();
- }
- this._builder.add('default:');
- this._builder.indent();
- this._builder.add("reader.skipType(tag & 7);");
- this._builder.add("break;");
- this._builder.outdent();
- this._builder.outdent();
- this._builder.add("}");
- this._builder.outdent();
- this._builder.add('}');
- for (const field of Array.from(type.fields.values()).filter((field) => field.required)) {
- this._builder.add(`if (!Object.prototype.hasOwnProperty.call(message, '${field.name}')) {`);
- this._builder.indent();
- this._builder.add(`throw new Error("Expected '${field.name}'.");`);
- this._builder.outdent();
- this._builder.add('}');
- }
- this._builder.add('return message;');
- this._builder.outdent();
- this._builder.add('}');
- /* eslint-enable indent */
- }
- _buildDecodeTextFunction(type) {
- /* eslint-disable indent */
- this._builder.add('static decodeText(reader) {');
- this._builder.indent();
- if (type.fullName === 'google.protobuf.Any') {
- this._builder.add(`return reader.any(() => new ${type.fullName}());`);
- } else {
- this._builder.add(`const message = new ${type.fullName}();`);
- this._builder.add('reader.start();');
- this._builder.add('while (!reader.end()) {');
- this._builder.indent();
- this._builder.add('const tag = reader.tag();');
- this._builder.add('switch (tag) {');
- this._builder.indent();
- for (const field of type.fields.values()) {
- const variable = `message${protoc.Generator._propertyReference(field.name)}`;
- this._builder.add(`case "${field.name}":`);
- this._builder.indent();
- // Map fields
- if (field instanceof protoc.MapField) {
- const value = field.type instanceof protoc.PrimitiveType ?
- `reader.${field.type.name}()` :
- `${field.type.fullName}.decodeText(reader)`;
- this._builder.add(`reader.entry(${variable}, () => reader.${field.keyType.name}(), () => ${value});`);
- } else if (field.repeated) { // Repeated fields
- if (field.type instanceof protoc.Enum) {
- this._builder.add(`reader.array(${variable}, () => reader.enum(${field.type.fullName}));`);
- } else if (field.type instanceof protoc.PrimitiveType) {
- this._builder.add(`reader.array(${variable}, () => reader.${field.type.name}());`);
- } else if (field.type.fullName === 'google.protobuf.Any') {
- this._builder.add(`reader.anyarray(${variable}, () => new ${field.type.fullName}());`);
- } else {
- this._builder.add(`${variable}.push(${field.type.fullName}.decodeText(reader));`);
- }
- // Non-repeated
- } else if (field.type instanceof protoc.Enum) {
- this._builder.add(`${variable} = reader.enum(${field.type.fullName});`);
- } else if (field.type instanceof protoc.PrimitiveType) {
- this._builder.add(`${variable} = reader.${field.type.name}();`);
- } else {
- this._builder.add(`${variable} = ${field.type.fullName}.decodeText(reader);`);
- }
- this._builder.add("break;");
- this._builder.outdent();
- }
- this._builder.add("default:");
- this._builder.indent();
- this._builder.add("reader.field(tag, message);");
- this._builder.add("break;");
- this._builder.outdent();
- this._builder.outdent();
- this._builder.add('}');
- this._builder.outdent();
- this._builder.add('}');
- for (const field of Array.from(type.fields.values()).filter((field) => field.required)) {
- this._builder.add(`if (!Object.prototype.hasOwnProperty.call(message, "${field.name}")) {`);
- this._builder.indent();
- this._builder.add(`throw new Error("Expected '${field.name}'.");`);
- this._builder.outdent();
- this._builder.add('}');
- }
- this._builder.add('return message;');
- }
- this._builder.outdent();
- this._builder.add('}');
- /* eslint-enable indent */
- }
- _buildDecodeJsonFunction(type) {
- /* eslint-disable indent */
- this._builder.add(`static decodeJson(${type.fullName === 'google.protobuf.Any' || type.fields.size === 0 ? '' : 'obj'}) {`);
- this._builder.indent();
- if (type.fullName === 'google.protobuf.Any') {
- this._builder.add("throw new Error('Any fields not implemented.');");
- } else {
- this._builder.add(`const message = new ${type.fullName}();`);
- for (const field of type.fields.values()) {
- const json = field.name.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
- const source = `obj.${json}`;
- const target = `message${protoc.Generator._propertyReference(field.name)}`;
- if (!field.required) {
- this._builder.add(`if ('${json}' in obj) {`);
- this._builder.indent();
- }
- if (field instanceof protoc.MapField) {
- this._builder.add(`for (const [key, value] of Object.entries(obj.${json})) {`);
- this._builder.indent();
- const value = field.type instanceof protoc.PrimitiveType ? `value` : `${field.type.fullName}.decodeJson(value)`;
- this._builder.add(`${target}[key] = ${value};`);
- this._builder.outdent();
- this._builder.add(`}`);
- } else if (field.repeated) {
- if (field.type instanceof protoc.PrimitiveType) {
- if (field.type.name === 'float' || field.type.name === 'double' || field.type.name === 'int32' || field.type.name === 'uint32') {
- this._builder.add(`${target} = ${source}.map((obj) => Number(obj));`);
- } else if (field.type.name === 'int64' || field.type.name === 'uint64' || field.type.name === 'fixed64' || field.type.name === 'sint64') {
- this._builder.add(`${target} = ${source}.map((obj) => BigInt(obj));`);
- } else if (field.type.name === 'bytes') {
- this._builder.add(`${target} = ${source}.map((obj) => typeof obj === 'string' ? Uint8Array.from(atob(obj), (c) => c.charCodeAt(0)) : Uint8Array.from(obj));`);
- } else if (field.type.name === 'string' || field.type.name === 'bool') {
- this._builder.add(`${target} = ${source};`);
- } else {
- throw new protoc.Error(`Repeated primitive field type '${field.type.name}' not implemented.`);
- }
- } else if (field.type instanceof protoc.Enum) {
- this._builder.add(`${target} = ${source}.map((key) => typeof key === 'string' ? ${field.type.fullName}[key] : key);`);
- } else {
- this._builder.add(`${target} = ${source}.map((obj) => ${field.type.fullName}.decodeJson(obj));`);
- }
- } else if (field.type instanceof protoc.PrimitiveType) {
- if (field.type.name === 'float' || field.type.name === 'double' || field.type.name === 'int32' || field.type.name === 'uint32' || field.type.name === 'fixed32') {
- this._builder.add(`${target} = Number(${source});`);
- } else if (field.type.name === 'int64' || field.type.name === 'uint64' || field.type.name === 'fixed64' || field.type.name === 'sint64') {
- this._builder.add(`${target} = BigInt(${source});`);
- } else if (field.type.name === 'bytes') {
- this._builder.add(`${target} = typeof ${source} === 'string' ? Uint8Array.from(atob(${source}), (c) => c.charCodeAt(0)) : Uint8Array.from(${source});`);
- } else if (field.type.name === 'string' || field.type.name === 'bool') {
- this._builder.add(`${target} = ${source};`);
- } else {
- throw new protoc.Error(`Primitive field type '${field.type.name}' not implemented.`);
- }
- } else if (field.type instanceof protoc.Enum) {
- this._builder.add(`${target} = typeof ${source} === 'string' ? ${field.type.fullName}[${source}] : ${source};`);
- } else {
- this._builder.add(`${target} = ${field.type.fullName}.decodeJson(${source});`);
- }
- if (!field.required) {
- this._builder.outdent();
- this._builder.add('}');
- }
- }
- this._builder.add('return message;');
- }
- this._builder.outdent();
- this._builder.add('}');
- /* eslint-enable indent */
- }
- static _isKeyword(name) {
- 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);
- }
- static _escapeName(name) {
- return protoc.Generator._isKeyword(name) ? `${name}_` : name;
- }
- static _propertyReference(name) {
- if (!/^[$\w_]+$/.test(name)) {
- return `["${name.replace(/\\/g, '\\\\').replace(/"/g, "\\\"")}"]`;
- }
- return `.${name}`;
- }
- };
- protoc.Generator.StringBuilder = class {
- constructor() {
- this._indentation = '';
- this._lines = [''];
- this._newline = true;
- }
- indent() {
- this._indentation += ' ';
- }
- outdent() {
- if (this._indentation.length === 0) {
- throw new protoc.Error('Invalid indentation.');
- }
- this._indentation = this._indentation.substring(0, this._indentation.length - 4);
- }
- add(text, newline) {
- if (this._newline) {
- if (text !== '') {
- this._lines.push(this._indentation);
- }
- }
- this._lines[this._lines.length - 1] = this._lines[this._lines.length - 1] + text + (newline === false ? '' : '\n');
- this._newline = newline === false ? false : true;
- }
- toString() {
- return this._lines.join('');
- }
- };
- protoc.Error = class extends Error {
- constructor(message) {
- super(message);
- this.name = 'Protocol Buffers Compiler Error';
- }
- };
- const main = async (args) => {
- const options = { verbose: false, root: 'default', out: '', text: false, paths: [], files: [] };
- while (args.length > 0) {
- const arg = args.shift();
- switch (arg) {
- case '--verbose':
- options.verbose = true;
- break;
- case '--out':
- options.out = args.shift();
- break;
- case '--root':
- options.root = args.shift();
- break;
- case '--binary':
- options.binary = true;
- break;
- case '--text':
- options.text = true;
- break;
- case '--json':
- options.json = true;
- break;
- case '--path':
- options.paths.push(args.shift());
- break;
- default:
- if (arg.startsWith('-')) {
- throw new protoc.Error(`Invalid command line argument '${arg}'.`);
- }
- options.files.push(arg);
- break;
- }
- }
- try {
- const root = new protoc.Root(options.root);
- await root.load(options.paths, options.files);
- const generator = new protoc.Generator(root, options);
- if (options.out) {
- await fs.writeFile(options.out, generator.content, 'utf-8');
- }
- } catch (error) {
- if (error instanceof protoc.Error && !options.verbose) {
- process.stderr.write(`${error.message}\n`);
- } else {
- process.stderr.write(`${error.stack}\n`);
- }
- process.exit(1);
- }
- process.exit(0);
- };
- if (typeof process === 'object' &&
- Array.isArray(process.argv) && process.argv.length > 1 &&
- path.basename(process.argv[1]) === 'protoc.js') {
- const args = process.argv.slice(2);
- await main(args);
- }
- export const Root = protoc.Root;
|