summaryrefslogtreecommitdiff
path: root/frontend-old/node_modules/protobufjs/src/parse.js
diff options
context:
space:
mode:
Diffstat (limited to 'frontend-old/node_modules/protobufjs/src/parse.js')
-rw-r--r--frontend-old/node_modules/protobufjs/src/parse.js969
1 files changed, 969 insertions, 0 deletions
diff --git a/frontend-old/node_modules/protobufjs/src/parse.js b/frontend-old/node_modules/protobufjs/src/parse.js
new file mode 100644
index 0000000..9c3cc27
--- /dev/null
+++ b/frontend-old/node_modules/protobufjs/src/parse.js
@@ -0,0 +1,969 @@
+"use strict";
+module.exports = parse;
+
+parse.filename = null;
+parse.defaults = { keepCase: false };
+
+var tokenize = require("./tokenize"),
+ Root = require("./root"),
+ Type = require("./type"),
+ Field = require("./field"),
+ MapField = require("./mapfield"),
+ OneOf = require("./oneof"),
+ Enum = require("./enum"),
+ Service = require("./service"),
+ Method = require("./method"),
+ ReflectionObject = require("./object"),
+ types = require("./types"),
+ util = require("./util");
+
+var base10Re = /^[1-9][0-9]*$/,
+ base10NegRe = /^-?[1-9][0-9]*$/,
+ base16Re = /^0[x][0-9a-fA-F]+$/,
+ base16NegRe = /^-?0[x][0-9a-fA-F]+$/,
+ base8Re = /^0[0-7]+$/,
+ base8NegRe = /^-?0[0-7]+$/,
+ numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/,
+ nameRe = /^[a-zA-Z_][a-zA-Z_0-9]*$/,
+ typeRefRe = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/;
+
+/**
+ * Result object returned from {@link parse}.
+ * @interface IParserResult
+ * @property {string|undefined} package Package name, if declared
+ * @property {string[]|undefined} imports Imports, if any
+ * @property {string[]|undefined} weakImports Weak imports, if any
+ * @property {Root} root Populated root instance
+ */
+
+/**
+ * Options modifying the behavior of {@link parse}.
+ * @interface IParseOptions
+ * @property {boolean} [keepCase=false] Keeps field casing instead of converting to camel case
+ * @property {boolean} [alternateCommentMode=false] Recognize double-slash comments in addition to doc-block comments.
+ * @property {boolean} [preferTrailingComment=false] Use trailing comment when both leading comment and trailing comment exist.
+ */
+
+/**
+ * Options modifying the behavior of JSON serialization.
+ * @interface IToJSONOptions
+ * @property {boolean} [keepComments=false] Serializes comments.
+ */
+
+/**
+ * Parses the given .proto source and returns an object with the parsed contents.
+ * @param {string} source Source contents
+ * @param {Root} root Root to populate
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {IParserResult} Parser result
+ * @property {string} filename=null Currently processing file name for error reporting, if known
+ * @property {IParseOptions} defaults Default {@link IParseOptions}
+ */
+function parse(source, root, options) {
+ /* eslint-disable callback-return */
+ if (!(root instanceof Root)) {
+ options = root;
+ root = new Root();
+ }
+ if (!options)
+ options = parse.defaults;
+
+ var preferTrailingComment = options.preferTrailingComment || false;
+ var tn = tokenize(source, options.alternateCommentMode || false),
+ next = tn.next,
+ push = tn.push,
+ peek = tn.peek,
+ skip = tn.skip,
+ cmnt = tn.cmnt;
+
+ var head = true,
+ pkg,
+ imports,
+ weakImports,
+ edition = "proto2";
+
+ var ptr = root;
+
+ var topLevelObjects = [];
+ var topLevelOptions = {};
+
+ var applyCase = options.keepCase ? function(name) { return name; } : util.camelCase;
+
+ function resolveFileFeatures() {
+ topLevelObjects.forEach(obj => {
+ obj._edition = edition;
+ Object.keys(topLevelOptions).forEach(opt => {
+ if (obj.getOption(opt) !== undefined) return;
+ obj.setOption(opt, topLevelOptions[opt], true);
+ });
+ });
+ }
+
+ /* istanbul ignore next */
+ function illegal(token, name, insideTryCatch) {
+ var filename = parse.filename;
+ if (!insideTryCatch)
+ parse.filename = null;
+ return Error("illegal " + (name || "token") + " '" + token + "' (" + (filename ? filename + ", " : "") + "line " + tn.line + ")");
+ }
+
+ function readString() {
+ var values = [],
+ token;
+ do {
+ /* istanbul ignore if */
+ if ((token = next()) !== "\"" && token !== "'")
+ throw illegal(token);
+
+ values.push(next());
+ skip(token);
+ token = peek();
+ } while (token === "\"" || token === "'");
+ return values.join("");
+ }
+
+ function readValue(acceptTypeRef) {
+ var token = next();
+ switch (token) {
+ case "'":
+ case "\"":
+ push(token);
+ return readString();
+ case "true": case "TRUE":
+ return true;
+ case "false": case "FALSE":
+ return false;
+ }
+ try {
+ return parseNumber(token, /* insideTryCatch */ true);
+ } catch (e) {
+ /* istanbul ignore else */
+ if (acceptTypeRef && typeRefRe.test(token))
+ return token;
+
+ /* istanbul ignore next */
+ throw illegal(token, "value");
+ }
+ }
+
+ function readRanges(target, acceptStrings) {
+ var token, start;
+ do {
+ if (acceptStrings && ((token = peek()) === "\"" || token === "'")) {
+ var str = readString();
+ target.push(str);
+ if (edition >= 2023) {
+ throw illegal(str, "id");
+ }
+ } else {
+ try {
+ target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
+ } catch (err) {
+ if (acceptStrings && typeRefRe.test(token) && edition >= 2023) {
+ target.push(token);
+ } else {
+ throw err;
+ }
+ }
+ }
+ } while (skip(",", true));
+ var dummy = {options: undefined};
+ dummy.setOption = function(name, value) {
+ if (this.options === undefined) this.options = {};
+ this.options[name] = value;
+ };
+ ifBlock(
+ dummy,
+ function parseRange_block(token) {
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(dummy, token); // skip
+ skip(";");
+ } else
+ throw illegal(token);
+ },
+ function parseRange_line() {
+ parseInlineOptions(dummy); // skip
+ });
+ }
+
+ function parseNumber(token, insideTryCatch) {
+ var 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;
+ }
+ if (base10Re.test(token))
+ return sign * parseInt(token, 10);
+ if (base16Re.test(token))
+ return sign * parseInt(token, 16);
+ if (base8Re.test(token))
+ return sign * parseInt(token, 8);
+
+ /* istanbul ignore else */
+ if (numberRe.test(token))
+ return sign * parseFloat(token);
+
+ /* istanbul ignore next */
+ throw illegal(token, "number", insideTryCatch);
+ }
+
+ function parseId(token, acceptNegative) {
+ switch (token) {
+ case "max": case "MAX": case "Max":
+ return 536870911;
+ case "0":
+ return 0;
+ }
+
+ /* istanbul ignore if */
+ if (!acceptNegative && token.charAt(0) === "-")
+ throw illegal(token, "id");
+
+ if (base10NegRe.test(token))
+ return parseInt(token, 10);
+ if (base16NegRe.test(token))
+ return parseInt(token, 16);
+
+ /* istanbul ignore else */
+ if (base8NegRe.test(token))
+ return parseInt(token, 8);
+
+ /* istanbul ignore next */
+ throw illegal(token, "id");
+ }
+
+ function parsePackage() {
+ /* istanbul ignore if */
+ if (pkg !== undefined)
+ throw illegal("package");
+
+ pkg = next();
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(pkg))
+ throw illegal(pkg, "name");
+
+ ptr = ptr.define(pkg);
+
+ skip(";");
+ }
+
+ function parseImport() {
+ var token = peek();
+ var whichImports;
+ switch (token) {
+ case "weak":
+ whichImports = weakImports || (weakImports = []);
+ next();
+ break;
+ case "public":
+ next();
+ // eslint-disable-next-line no-fallthrough
+ default:
+ whichImports = imports || (imports = []);
+ break;
+ }
+ token = readString();
+ skip(";");
+ whichImports.push(token);
+ }
+
+ function parseSyntax() {
+ skip("=");
+ edition = readString();
+
+ /* istanbul ignore if */
+ if (edition < 2023)
+ throw illegal(edition, "syntax");
+
+ skip(";");
+ }
+
+ function parseEdition() {
+ skip("=");
+ edition = readString();
+ const supportedEditions = ["2023"];
+
+ /* istanbul ignore if */
+ if (!supportedEditions.includes(edition))
+ throw illegal(edition, "edition");
+
+ skip(";");
+ }
+
+
+ function parseCommon(parent, token) {
+ switch (token) {
+
+ case "option":
+ parseOption(parent, token);
+ skip(";");
+ return true;
+
+ case "message":
+ parseType(parent, token);
+ return true;
+
+ case "enum":
+ parseEnum(parent, token);
+ return true;
+
+ case "service":
+ parseService(parent, token);
+ return true;
+
+ case "extend":
+ parseExtension(parent, token);
+ return true;
+ }
+ return false;
+ }
+
+ function ifBlock(obj, fnIf, fnElse) {
+ var trailingLine = tn.line;
+ if (obj) {
+ if(typeof obj.comment !== "string") {
+ obj.comment = cmnt(); // try block-type comment
+ }
+ obj.filename = parse.filename;
+ }
+ if (skip("{", true)) {
+ var token;
+ while ((token = next()) !== "}")
+ fnIf(token);
+ skip(";", true);
+ } else {
+ if (fnElse)
+ fnElse();
+ skip(";");
+ if (obj && (typeof obj.comment !== "string" || preferTrailingComment))
+ obj.comment = cmnt(trailingLine) || obj.comment; // try line-type comment
+ }
+ }
+
+ function parseType(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "type name");
+
+ var type = new Type(token);
+ ifBlock(type, function parseType_block(token) {
+ if (parseCommon(type, token))
+ return;
+
+ switch (token) {
+
+ case "map":
+ parseMapField(type, token);
+ break;
+
+ case "required":
+ if (edition !== "proto2")
+ throw illegal(token);
+ /* eslint-disable no-fallthrough */
+ case "repeated":
+ parseField(type, token);
+ break;
+
+ case "optional":
+ /* istanbul ignore if */
+ if (edition === "proto3") {
+ parseField(type, "proto3_optional");
+ } else if (edition !== "proto2") {
+ throw illegal(token);
+ } else {
+ parseField(type, "optional");
+ }
+ break;
+
+ case "oneof":
+ parseOneOf(type, token);
+ break;
+
+ case "extensions":
+ readRanges(type.extensions || (type.extensions = []));
+ break;
+
+ case "reserved":
+ readRanges(type.reserved || (type.reserved = []), true);
+ break;
+
+ default:
+ /* istanbul ignore if */
+ if (edition === "proto2" || !typeRefRe.test(token)) {
+ throw illegal(token);
+ }
+
+ push(token);
+ parseField(type, "optional");
+ break;
+ }
+ });
+ parent.add(type);
+ if (parent === ptr) {
+ topLevelObjects.push(type);
+ }
+ }
+
+ function parseField(parent, rule, extend) {
+ var type = next();
+ if (type === "group") {
+ parseGroup(parent, rule);
+ return;
+ }
+ // Type names can consume multiple tokens, in multiple variants:
+ // package.subpackage field tokens: "package.subpackage" [TYPE NAME ENDS HERE] "field"
+ // package . subpackage field tokens: "package" "." "subpackage" [TYPE NAME ENDS HERE] "field"
+ // package. subpackage field tokens: "package." "subpackage" [TYPE NAME ENDS HERE] "field"
+ // package .subpackage field tokens: "package" ".subpackage" [TYPE NAME ENDS HERE] "field"
+ // Keep reading tokens until we get a type name with no period at the end,
+ // and the next token does not start with a period.
+ while (type.endsWith(".") || peek().startsWith(".")) {
+ type += next();
+ }
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(type))
+ throw illegal(type, "type");
+
+ var name = next();
+
+ /* istanbul ignore if */
+
+ if (!nameRe.test(name))
+ throw illegal(name, "name");
+
+ name = applyCase(name);
+ skip("=");
+
+ var field = new Field(name, parseId(next()), type, rule, extend);
+
+ ifBlock(field, function parseField_block(token) {
+
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(field, token);
+ skip(";");
+ } else
+ throw illegal(token);
+
+ }, function parseField_line() {
+ parseInlineOptions(field);
+ });
+
+ if (rule === "proto3_optional") {
+ // for proto3 optional fields, we create a single-member Oneof to mimic "optional" behavior
+ var oneof = new OneOf("_" + name);
+ field.setOption("proto3_optional", true);
+ oneof.add(field);
+ parent.add(oneof);
+ } else {
+ parent.add(field);
+ }
+ if (parent === ptr) {
+ topLevelObjects.push(field);
+ }
+ }
+
+ function parseGroup(parent, rule) {
+ if (edition >= 2023) {
+ throw illegal("group");
+ }
+ var name = next();
+
+ /* istanbul ignore if */
+ if (!nameRe.test(name))
+ throw illegal(name, "name");
+
+ var fieldName = util.lcFirst(name);
+ if (name === fieldName)
+ name = util.ucFirst(name);
+ skip("=");
+ var id = parseId(next());
+ var type = new Type(name);
+ type.group = true;
+ var field = new Field(fieldName, id, name, rule);
+ field.filename = parse.filename;
+ ifBlock(type, function parseGroup_block(token) {
+ switch (token) {
+
+ case "option":
+ parseOption(type, token);
+ skip(";");
+ break;
+ case "required":
+ case "repeated":
+ parseField(type, token);
+ break;
+
+ case "optional":
+ /* istanbul ignore if */
+ if (edition === "proto3") {
+ parseField(type, "proto3_optional");
+ } else {
+ parseField(type, "optional");
+ }
+ break;
+
+ case "message":
+ parseType(type, token);
+ break;
+
+ case "enum":
+ parseEnum(type, token);
+ break;
+
+ case "reserved":
+ readRanges(type.reserved || (type.reserved = []), true);
+ break;
+
+ /* istanbul ignore next */
+ default:
+ throw illegal(token); // there are no groups with proto3 semantics
+ }
+ });
+ parent.add(type)
+ .add(field);
+ }
+
+ function parseMapField(parent) {
+ skip("<");
+ var keyType = next();
+
+ /* istanbul ignore if */
+ if (types.mapKey[keyType] === undefined)
+ throw illegal(keyType, "type");
+
+ skip(",");
+ var valueType = next();
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(valueType))
+ throw illegal(valueType, "type");
+
+ skip(">");
+ var name = next();
+
+ /* istanbul ignore if */
+ if (!nameRe.test(name))
+ throw illegal(name, "name");
+
+ skip("=");
+ var field = new MapField(applyCase(name), parseId(next()), keyType, valueType);
+ ifBlock(field, function parseMapField_block(token) {
+
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(field, token);
+ skip(";");
+ } else
+ throw illegal(token);
+
+ }, function parseMapField_line() {
+ parseInlineOptions(field);
+ });
+ parent.add(field);
+ }
+
+ function parseOneOf(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "name");
+
+ var oneof = new OneOf(applyCase(token));
+ ifBlock(oneof, function parseOneOf_block(token) {
+ if (token === "option") {
+ parseOption(oneof, token);
+ skip(";");
+ } else {
+ push(token);
+ parseField(oneof, "optional");
+ }
+ });
+ parent.add(oneof);
+ }
+
+ function parseEnum(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "name");
+
+ var enm = new Enum(token);
+ ifBlock(enm, function parseEnum_block(token) {
+ switch(token) {
+ case "option":
+ parseOption(enm, token);
+ skip(";");
+ break;
+
+ case "reserved":
+ readRanges(enm.reserved || (enm.reserved = []), true);
+ if(enm.reserved === undefined) enm.reserved = [];
+ break;
+
+ default:
+ parseEnumValue(enm, token);
+ }
+ });
+ parent.add(enm);
+ if (parent === ptr) {
+ topLevelObjects.push(enm);
+ }
+ }
+
+ function parseEnumValue(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token))
+ throw illegal(token, "name");
+
+ skip("=");
+ var value = parseId(next(), true),
+ dummy = {
+ options: undefined
+ };
+ dummy.getOption = function(name) {
+ return this.options[name];
+ };
+ dummy.setOption = function(name, value) {
+ ReflectionObject.prototype.setOption.call(dummy, name, value);
+ };
+ dummy.setParsedOption = function() {
+ return undefined;
+ };
+ ifBlock(dummy, function parseEnumValue_block(token) {
+
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(dummy, token); // skip
+ skip(";");
+ } else
+ throw illegal(token);
+
+ }, function parseEnumValue_line() {
+ parseInlineOptions(dummy); // skip
+ });
+ parent.add(token, value, dummy.comment, dummy.parsedOptions || dummy.options);
+ }
+
+ function parseOption(parent, token) {
+ var option;
+ var propName;
+ var isOption = true;
+ if (token === "option") {
+ token = next();
+ }
+
+ while (token !== "=") {
+ if (token === "(") {
+ var parensValue = next();
+ skip(")");
+ token = "(" + parensValue + ")";
+ }
+ if (isOption) {
+ isOption = false;
+ if (token.includes(".") && !token.includes("(")) {
+ var tokens = token.split(".");
+ option = tokens[0] + ".";
+ token = tokens[1];
+ continue;
+ }
+ option = token;
+ } else {
+ propName = propName ? propName += token : token;
+ }
+ token = next();
+ }
+ var name = propName ? option.concat(propName) : option;
+ var optionValue = parseOptionValue(parent, name);
+ propName = propName && propName[0] === "." ? propName.slice(1) : propName;
+ option = option && option[option.length - 1] === "." ? option.slice(0, -1) : option;
+ setParsedOption(parent, option, optionValue, propName);
+ }
+
+ function parseOptionValue(parent, name) {
+ // { a: "foo" b { c: "bar" } }
+ if (skip("{", true)) {
+ var objectResult = {};
+
+ while (!skip("}", true)) {
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next())) {
+ throw illegal(token, "name");
+ }
+ if (token === null) {
+ throw illegal(token, "end of input");
+ }
+
+ var value;
+ var propName = token;
+
+ skip(":", true);
+
+ if (peek() === "{") {
+ // option (my_option) = {
+ // repeated_value: [ "foo", "bar" ]
+ // };
+ value = parseOptionValue(parent, name + "." + token);
+ } else if (peek() === "[") {
+ value = [];
+ var lastValue;
+ if (skip("[", true)) {
+ do {
+ lastValue = readValue(true);
+ value.push(lastValue);
+ } while (skip(",", true));
+ skip("]");
+ if (typeof lastValue !== "undefined") {
+ setOption(parent, name + "." + token, lastValue);
+ }
+ }
+ } else {
+ value = readValue(true);
+ setOption(parent, name + "." + token, value);
+ }
+
+ var prevValue = objectResult[propName];
+
+ if (prevValue)
+ value = [].concat(prevValue).concat(value);
+
+ objectResult[propName] = value;
+
+ // Semicolons and commas can be optional
+ skip(",", true);
+ skip(";", true);
+ }
+
+ return objectResult;
+ }
+
+ var simpleValue = readValue(true);
+ setOption(parent, name, simpleValue);
+ return simpleValue;
+ // Does not enforce a delimiter to be universal
+ }
+
+ function setOption(parent, name, value) {
+ if (ptr === parent && /^features\./.test(name)) {
+ topLevelOptions[name] = value;
+ return;
+ }
+ if (parent.setOption)
+ parent.setOption(name, value);
+ }
+
+ function setParsedOption(parent, name, value, propName) {
+ if (parent.setParsedOption)
+ parent.setParsedOption(name, value, propName);
+ }
+
+ function parseInlineOptions(parent) {
+ if (skip("[", true)) {
+ do {
+ parseOption(parent, "option");
+ } while (skip(",", true));
+ skip("]");
+ }
+ return parent;
+ }
+
+ function parseService(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "service name");
+
+ var service = new Service(token);
+ ifBlock(service, function parseService_block(token) {
+ if (parseCommon(service, token)) {
+ return;
+ }
+
+ /* istanbul ignore else */
+ if (token === "rpc")
+ parseMethod(service, token);
+ else
+ throw illegal(token);
+ });
+ parent.add(service);
+ if (parent === ptr) {
+ topLevelObjects.push(service);
+ }
+ }
+
+ function parseMethod(parent, token) {
+ // Get the comment of the preceding line now (if one exists) in case the
+ // method is defined across multiple lines.
+ var commentText = cmnt();
+
+ var type = token;
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "name");
+
+ var name = token,
+ requestType, requestStream,
+ responseType, responseStream;
+
+ skip("(");
+ if (skip("stream", true))
+ requestStream = true;
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(token = next()))
+ throw illegal(token);
+
+ requestType = token;
+ skip(")"); skip("returns"); skip("(");
+ if (skip("stream", true))
+ responseStream = true;
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(token = next()))
+ throw illegal(token);
+
+ responseType = token;
+ skip(")");
+
+ var method = new Method(name, type, requestType, responseType, requestStream, responseStream);
+ method.comment = commentText;
+ ifBlock(method, function parseMethod_block(token) {
+
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(method, token);
+ skip(";");
+ } else
+ throw illegal(token);
+
+ });
+ parent.add(method);
+ }
+
+ function parseExtension(parent, token) {
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(token = next()))
+ throw illegal(token, "reference");
+
+ var reference = token;
+ ifBlock(null, function parseExtension_block(token) {
+ switch (token) {
+
+ case "required":
+ case "repeated":
+ parseField(parent, token, reference);
+ break;
+
+ case "optional":
+ /* istanbul ignore if */
+ if (edition === "proto3") {
+ parseField(parent, "proto3_optional", reference);
+ } else {
+ parseField(parent, "optional", reference);
+ }
+ break;
+
+ default:
+ /* istanbul ignore if */
+ if (edition === "proto2" || !typeRefRe.test(token))
+ throw illegal(token);
+ push(token);
+ parseField(parent, "optional", reference);
+ break;
+ }
+ });
+ }
+
+ var token;
+ while ((token = next()) !== null) {
+ switch (token) {
+
+ case "package":
+
+ /* istanbul ignore if */
+ if (!head)
+ throw illegal(token);
+
+ parsePackage();
+ break;
+
+ case "import":
+
+ /* istanbul ignore if */
+ if (!head)
+ throw illegal(token);
+
+ parseImport();
+ break;
+
+ case "syntax":
+
+ /* istanbul ignore if */
+ if (!head)
+ throw illegal(token);
+
+ parseSyntax();
+ break;
+
+ case "edition":
+ /* istanbul ignore if */
+ if (!head)
+ throw illegal(token);
+ parseEdition();
+ break;
+
+ case "option":
+ parseOption(ptr, token);
+ skip(";", true);
+ break;
+
+ default:
+
+ /* istanbul ignore else */
+ if (parseCommon(ptr, token)) {
+ head = false;
+ continue;
+ }
+
+ /* istanbul ignore next */
+ throw illegal(token);
+ }
+ }
+
+ resolveFileFeatures();
+
+ parse.filename = null;
+ return {
+ "package" : pkg,
+ "imports" : imports,
+ weakImports : weakImports,
+ root : root
+ };
+}
+
+/**
+ * Parses the given .proto source and returns an object with the parsed contents.
+ * @name parse
+ * @function
+ * @param {string} source Source contents
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {IParserResult} Parser result
+ * @property {string} filename=null Currently processing file name for error reporting, if known
+ * @property {IParseOptions} defaults Default {@link IParseOptions}
+ * @variation 2
+ */