dev testing
This commit is contained in:
969
functions/node_modules/protobufjs/src/parse.js
generated
vendored
Normal file
969
functions/node_modules/protobufjs/src/parse.js
generated
vendored
Normal file
@@ -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
|
||||
*/
|
||||
Reference in New Issue
Block a user