--- /dev/null
+"use strict";
+module.exports = static_target;
+
+var protobuf = require("../.."),
+ UglifyJS = require("uglify-js"),
+ espree = require("espree"),
+ escodegen = require("escodegen"),
+ estraverse = require("estraverse");
+
+var Type = protobuf.Type,
+ Service = protobuf.Service,
+ Enum = protobuf.Enum,
+ Namespace = protobuf.Namespace,
+ util = protobuf.util;
+
+var out = [];
+var indent = 0;
+var config = {};
+
+static_target.description = "Static code without reflection (non-functional on its own)";
+
+function static_target(root, options, callback) {
+ config = options;
+ try {
+ var aliases = [];
+ if (config.decode)
+ aliases.push("Reader");
+ if (config.encode)
+ aliases.push("Writer");
+ aliases.push("util");
+ if (aliases.length) {
+ if (config.comments)
+ push("// Common aliases");
+ push((config.es6 ? "const " : "var ") + aliases.map(function(name) { return "$" + name + " = $protobuf." + name; }).join(", ") + ";");
+ push("");
+ }
+ if (config.comments) {
+ if (root.comment) {
+ pushComment("@fileoverview " + root.comment);
+ push("");
+ }
+ push("// Exported root namespace");
+ }
+ var rootProp = util.safeProp(config.root || "default");
+ push((config.es6 ? "const" : "var") + " $root = $protobuf.roots" + rootProp + " || ($protobuf.roots" + rootProp + " = {});");
+ buildNamespace(null, root);
+ return callback(null, out.join("\n"));
+ } catch (err) {
+ return callback(err);
+ } finally {
+ out = [];
+ indent = 0;
+ config = {};
+ }
+}
+
+function push(line) {
+ if (line === "")
+ return out.push("");
+ var ind = "";
+ for (var i = 0; i < indent; ++i)
+ ind += " ";
+ return out.push(ind + line);
+}
+
+function pushComment(lines) {
+ if (!config.comments)
+ return;
+ var split = [];
+ for (var i = 0; i < lines.length; ++i)
+ if (lines[i] != null && lines[i].substring(0, 8) !== "@exclude")
+ Array.prototype.push.apply(split, lines[i].split(/\r?\n/g));
+ push("/**");
+ split.forEach(function(line) {
+ if (line === null)
+ return;
+ push(" * " + line.replace(/\*\//g, "* /"));
+ });
+ push(" */");
+}
+
+function exportName(object, asInterface) {
+ if (asInterface) {
+ if (object.__interfaceName)
+ return object.__interfaceName;
+ } else if (object.__exportName)
+ return object.__exportName;
+ var parts = object.fullName.substring(1).split("."),
+ i = 0;
+ while (i < parts.length)
+ parts[i] = escapeName(parts[i++]);
+ if (asInterface)
+ parts[i - 1] = "I" + parts[i - 1];
+ return object[asInterface ? "__interfaceName" : "__exportName"] = parts.join(".");
+}
+
+function escapeName(name) {
+ if (!name)
+ return "$root";
+ return util.isReserved(name) ? name + "_" : name;
+}
+
+function aOrAn(name) {
+ return ((/^[hH](?:ou|on|ei)/.test(name) || /^[aeiouAEIOU][a-z]/.test(name)) && !/^us/i.test(name)
+ ? "an "
+ : "a ") + name;
+}
+
+function buildNamespace(ref, ns) {
+ if (!ns)
+ return;
+ if (ns.name !== "") {
+ push("");
+ if (!ref && config.es6)
+ push("export const " + escapeName(ns.name) + " = " + escapeName(ref) + "." + escapeName(ns.name) + " = (() => {");
+ else
+ push(escapeName(ref) + "." + escapeName(ns.name) + " = (function() {");
+ ++indent;
+ }
+
+ if (ns instanceof Type) {
+ buildType(undefined, ns);
+ } else if (ns instanceof Service)
+ buildService(undefined, ns);
+ else if (ns.name !== "") {
+ push("");
+ pushComment([
+ ns.comment || "Namespace " + ns.name + ".",
+ ns.parent instanceof protobuf.Root ? "@exports " + escapeName(ns.name) : "@memberof " + exportName(ns.parent),
+ "@namespace"
+ ]);
+ push((config.es6 ? "const" : "var") + " " + escapeName(ns.name) + " = {};");
+ }
+
+ ns.nestedArray.forEach(function(nested) {
+ if (nested instanceof Enum)
+ buildEnum(ns.name, nested);
+ else if (nested instanceof Namespace)
+ buildNamespace(ns.name, nested);
+ });
+ if (ns.name !== "") {
+ push("");
+ push("return " + escapeName(ns.name) + ";");
+ --indent;
+ push("})();");
+ }
+}
+
+var reduceableBlockStatements = {
+ IfStatement: true,
+ ForStatement: true,
+ WhileStatement: true
+};
+
+var shortVars = {
+ "r": "reader",
+ "w": "writer",
+ "m": "message",
+ "t": "tag",
+ "l": "length",
+ "c": "end", "c2": "end2",
+ "k": "key",
+ "ks": "keys", "ks2": "keys2",
+ "e": "error",
+ "f": "impl",
+ "o": "options",
+ "d": "object",
+ "n": "long",
+ "p": "properties"
+};
+
+function beautifyCode(code) {
+ // Add semicolons
+ code = UglifyJS.minify(code, {
+ compress: false,
+ mangle: false,
+ output: { beautify: true }
+ }).code;
+ // Properly beautify
+ var ast = espree.parse(code);
+ estraverse.replace(ast, {
+ enter: function(node, parent) {
+ // rename short vars
+ if (node.type === "Identifier" && (parent.property !== node || parent.computed) && shortVars[node.name])
+ return {
+ "type": "Identifier",
+ "name": shortVars[node.name]
+ };
+ // replace var with let if es6
+ if (config.es6 && node.type === "VariableDeclaration" && node.kind === "var") {
+ node.kind = "let";
+ return undefined;
+ }
+ // remove braces around block statements with a single child
+ if (node.type === "BlockStatement" && reduceableBlockStatements[parent.type] && node.body.length === 1)
+ return node.body[0];
+ return undefined;
+ }
+ });
+ code = escodegen.generate(ast, {
+ format: {
+ newline: "\n",
+ quotes: "double"
+ }
+ });
+ // Add id, wireType comments
+ if (config.comments)
+ code = code.replace(/\.uint32\((\d+)\)/g, function($0, $1) {
+ var id = $1 >>> 3,
+ wireType = $1 & 7;
+ return ".uint32(/* id " + id + ", wireType " + wireType + " =*/" + $1 + ")";
+ });
+ return code;
+}
+
+var renameVars = {
+ "Writer": "$Writer",
+ "Reader": "$Reader",
+ "util": "$util"
+};
+
+function buildFunction(type, functionName, gen, scope) {
+ var code = gen.toString(functionName)
+ .replace(/((?!\.)types\[\d+])(\.values)/g, "$1"); // enums: use types[N] instead of reflected types[N].values
+
+ var ast = espree.parse(code);
+ /* eslint-disable no-extra-parens */
+ estraverse.replace(ast, {
+ enter: function(node, parent) {
+ // rename vars
+ if (
+ node.type === "Identifier" && renameVars[node.name]
+ && (
+ (parent.type === "MemberExpression" && parent.object === node)
+ || (parent.type === "BinaryExpression" && parent.right === node)
+ )
+ )
+ return {
+ "type": "Identifier",
+ "name": renameVars[node.name]
+ };
+ // replace this.ctor with the actual ctor
+ if (
+ node.type === "MemberExpression"
+ && node.object.type === "ThisExpression"
+ && node.property.type === "Identifier" && node.property.name === "ctor"
+ )
+ return {
+ "type": "Identifier",
+ "name": "$root" + type.fullName
+ };
+ // replace types[N] with the field's actual type
+ if (
+ node.type === "MemberExpression"
+ && node.object.type === "Identifier" && node.object.name === "types"
+ && node.property.type === "Literal"
+ )
+ return {
+ "type": "Identifier",
+ "name": "$root" + type.fieldsArray[node.property.value].resolvedType.fullName
+ };
+ return undefined;
+ }
+ });
+ /* eslint-enable no-extra-parens */
+ code = escodegen.generate(ast, {
+ format: {
+ newline: "\n",
+ quotes: "double"
+ }
+ });
+
+ if (config.beautify)
+ code = beautifyCode(code);
+
+ code = code.replace(/ {4}/g, "\t");
+
+ var hasScope = scope && Object.keys(scope).length,
+ isCtor = functionName === type.name;
+
+ if (hasScope) // remove unused scope vars
+ Object.keys(scope).forEach(function(key) {
+ if (!new RegExp("\\b(" + key + ")\\b", "g").test(code))
+ delete scope[key];
+ });
+
+ var lines = code.split(/\n/g);
+ if (isCtor) // constructor
+ push(lines[0]);
+ else if (hasScope) // enclose in an iife
+ push(escapeName(type.name) + "." + escapeName(functionName) + " = (function(" + Object.keys(scope).map(escapeName).join(", ") + ") { return " + lines[0]);
+ else
+ push(escapeName(type.name) + "." + escapeName(functionName) + " = " + lines[0]);
+ lines.slice(1, lines.length - 1).forEach(function(line) {
+ var prev = indent;
+ var i = 0;
+ while (line.charAt(i++) === "\t")
+ ++indent;
+ push(line.trim());
+ indent = prev;
+ });
+ if (isCtor)
+ push("}");
+ else if (hasScope)
+ push("};})(" + Object.keys(scope).map(function(key) { return scope[key]; }).join(", ") + ");");
+ else
+ push("};");
+}
+
+function toJsType(field) {
+ var type;
+
+ switch (field.type) {
+ case "double":
+ case "float":
+ case "int32":
+ case "uint32":
+ case "sint32":
+ case "fixed32":
+ case "sfixed32":
+ type = "number";
+ break;
+ case "int64":
+ case "uint64":
+ case "sint64":
+ case "fixed64":
+ case "sfixed64":
+ type = config.forceLong ? "Long" : config.forceNumber ? "number" : "number|Long";
+ break;
+ case "bool":
+ type = "boolean";
+ break;
+ case "string":
+ type = "string";
+ break;
+ case "bytes":
+ type = "Uint8Array";
+ break;
+ default:
+ if (field.resolve().resolvedType)
+ type = exportName(field.resolvedType, !(field.resolvedType instanceof protobuf.Enum || config.forceMessage));
+ else
+ type = "*"; // should not happen
+ break;
+ }
+ if (field.map)
+ return "Object.<string," + type + ">";
+ if (field.repeated)
+ return "Array.<" + type + ">";
+ return type;
+}
+
+function buildType(ref, type) {
+
+ if (config.comments) {
+ var typeDef = [
+ "Properties of " + aOrAn(type.name) + ".",
+ type.parent instanceof protobuf.Root ? "@exports " + escapeName("I" + type.name) : "@memberof " + exportName(type.parent),
+ "@interface " + escapeName("I" + type.name)
+ ];
+ type.fieldsArray.forEach(function(field) {
+ var prop = util.safeProp(field.name); // either .name or ["name"]
+ prop = prop.substring(1, prop.charAt(0) === "[" ? prop.length - 1 : prop.length);
+ var jsType = toJsType(field);
+ if (field.optional)
+ jsType = jsType + "|null";
+ typeDef.push("@property {" + jsType + "} " + (field.optional ? "[" + prop + "]" : prop) + " " + (field.comment || type.name + " " + field.name));
+ });
+ push("");
+ pushComment(typeDef);
+ }
+
+ // constructor
+ push("");
+ pushComment([
+ "Constructs a new " + type.name + ".",
+ type.parent instanceof protobuf.Root ? "@exports " + escapeName(type.name) : "@memberof " + exportName(type.parent),
+ "@classdesc " + (type.comment || "Represents " + aOrAn(type.name) + "."),
+ config.comments ? "@implements " + escapeName("I" + type.name) : null,
+ "@constructor",
+ "@param {" + exportName(type, true) + "=} [" + (config.beautify ? "properties" : "p") + "] Properties to set"
+ ]);
+ buildFunction(type, type.name, Type.generateConstructor(type));
+
+ // default values
+ var firstField = true;
+ type.fieldsArray.forEach(function(field) {
+ field.resolve();
+ var prop = util.safeProp(field.name);
+ if (config.comments) {
+ push("");
+ var jsType = toJsType(field);
+ if (field.optional && !field.map && !field.repeated && field.resolvedType instanceof Type)
+ jsType = jsType + "|null|undefined";
+ pushComment([
+ field.comment || type.name + " " + field.name + ".",
+ "@member {" + jsType + "} " + field.name,
+ "@memberof " + exportName(type),
+ "@instance"
+ ]);
+ } else if (firstField) {
+ push("");
+ firstField = false;
+ }
+ if (field.repeated)
+ push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyArray;"); // overwritten in constructor
+ else if (field.map)
+ push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyObject;"); // overwritten in constructor
+ else if (field.long)
+ push(escapeName(type.name) + ".prototype" + prop + " = $util.Long ? $util.Long.fromBits("
+ + JSON.stringify(field.typeDefault.low) + ","
+ + JSON.stringify(field.typeDefault.high) + ","
+ + JSON.stringify(field.typeDefault.unsigned)
+ + ") : " + field.typeDefault.toNumber(field.type.charAt(0) === "u") + ";");
+ else if (field.bytes) {
+ push(escapeName(type.name) + ".prototype" + prop + " = $util.newBuffer(" + JSON.stringify(Array.prototype.slice.call(field.typeDefault)) + ");");
+ } else
+ push(escapeName(type.name) + ".prototype" + prop + " = " + JSON.stringify(field.typeDefault) + ";");
+ });
+
+ // virtual oneof fields
+ var firstOneOf = true;
+ type.oneofsArray.forEach(function(oneof) {
+ if (firstOneOf) {
+ firstOneOf = false;
+ push("");
+ if (config.comments)
+ push("// OneOf field names bound to virtual getters and setters");
+ push((config.es6 ? "let" : "var") + " $oneOfFields;");
+ }
+ oneof.resolve();
+ push("");
+ pushComment([
+ oneof.comment || type.name + " " + oneof.name + ".",
+ "@member {" + oneof.oneof.map(JSON.stringify).join("|") + "|undefined} " + escapeName(oneof.name),
+ "@memberof " + exportName(type),
+ "@instance"
+ ]);
+ push("Object.defineProperty(" + escapeName(type.name) + ".prototype, " + JSON.stringify(oneof.name) +", {");
+ ++indent;
+ push("get: $util.oneOfGetter($oneOfFields = [" + oneof.oneof.map(JSON.stringify).join(", ") + "]),");
+ push("set: $util.oneOfSetter($oneOfFields)");
+ --indent;
+ push("});");
+ });
+
+ if (config.create) {
+ push("");
+ pushComment([
+ "Creates a new " + type.name + " instance using the specified properties.",
+ "@function create",
+ "@memberof " + exportName(type),
+ "@static",
+ "@param {" + exportName(type, true) + "=} [properties] Properties to set",
+ "@returns {" + exportName(type) + "} " + type.name + " instance"
+ ]);
+ push(escapeName(type.name) + ".create = function create(properties) {");
+ ++indent;
+ push("return new " + escapeName(type.name) + "(properties);");
+ --indent;
+ push("};");
+ }
+
+ if (config.encode) {
+ push("");
+ pushComment([
+ "Encodes the specified " + type.name + " message. Does not implicitly {@link " + exportName(type) + ".verify|verify} messages.",
+ "@function encode",
+ "@memberof " + exportName(type),
+ "@static",
+ "@param {" + exportName(type, !config.forceMessage) + "} " + (config.beautify ? "message" : "m") + " " + type.name + " message or plain object to encode",
+ "@param {$protobuf.Writer} [" + (config.beautify ? "writer" : "w") + "] Writer to encode to",
+ "@returns {$protobuf.Writer} Writer"
+ ]);
+ buildFunction(type, "encode", protobuf.encoder(type));
+
+ if (config.delimited) {
+ push("");
+ pushComment([
+ "Encodes the specified " + type.name + " message, length delimited. Does not implicitly {@link " + exportName(type) + ".verify|verify} messages.",
+ "@function encodeDelimited",
+ "@memberof " + exportName(type),
+ "@static",
+ "@param {" + exportName(type, !config.forceMessage) + "} message " + type.name + " message or plain object to encode",
+ "@param {$protobuf.Writer} [writer] Writer to encode to",
+ "@returns {$protobuf.Writer} Writer"
+ ]);
+ push(escapeName(type.name) + ".encodeDelimited = function encodeDelimited(message, writer) {");
+ ++indent;
+ push("return this.encode(message, writer).ldelim();");
+ --indent;
+ push("};");
+ }
+ }
+
+ if (config.decode) {
+ push("");
+ pushComment([
+ "Decodes " + aOrAn(type.name) + " message from the specified reader or buffer.",
+ "@function decode",
+ "@memberof " + exportName(type),
+ "@static",
+ "@param {$protobuf.Reader|Uint8Array} " + (config.beautify ? "reader" : "r") + " Reader or buffer to decode from",
+ "@param {number} [" + (config.beautify ? "length" : "l") + "] Message length if known beforehand",
+ "@returns {" + exportName(type) + "} " + type.name,
+ "@throws {Error} If the payload is not a reader or valid buffer",
+ "@throws {$protobuf.util.ProtocolError} If required fields are missing"
+ ]);
+ buildFunction(type, "decode", protobuf.decoder(type));
+
+ if (config.delimited) {
+ push("");
+ pushComment([
+ "Decodes " + aOrAn(type.name) + " message from the specified reader or buffer, length delimited.",
+ "@function decodeDelimited",
+ "@memberof " + exportName(type),
+ "@static",
+ "@param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from",
+ "@returns {" + exportName(type) + "} " + type.name,
+ "@throws {Error} If the payload is not a reader or valid buffer",
+ "@throws {$protobuf.util.ProtocolError} If required fields are missing"
+ ]);
+ push(escapeName(type.name) + ".decodeDelimited = function decodeDelimited(reader) {");
+ ++indent;
+ push("if (!(reader instanceof $Reader))");
+ ++indent;
+ push("reader = new $Reader(reader);");
+ --indent;
+ push("return this.decode(reader, reader.uint32());");
+ --indent;
+ push("};");
+ }
+ }
+
+ if (config.verify) {
+ push("");
+ pushComment([
+ "Verifies " + aOrAn(type.name) + " message.",
+ "@function verify",
+ "@memberof " + exportName(type),
+ "@static",
+ "@param {Object.<string,*>} " + (config.beautify ? "message" : "m") + " Plain object to verify",
+ "@returns {string|null} `null` if valid, otherwise the reason why it is not"
+ ]);
+ buildFunction(type, "verify", protobuf.verifier(type));
+ }
+
+ if (config.convert) {
+ push("");
+ pushComment([
+ "Creates " + aOrAn(type.name) + " message from a plain object. Also converts values to their respective internal types.",
+ "@function fromObject",
+ "@memberof " + exportName(type),
+ "@static",
+ "@param {Object.<string,*>} " + (config.beautify ? "object" : "d") + " Plain object",
+ "@returns {" + exportName(type) + "} " + type.name
+ ]);
+ buildFunction(type, "fromObject", protobuf.converter.fromObject(type));
+
+ push("");
+ pushComment([
+ "Creates a plain object from " + aOrAn(type.name) + " message. Also converts values to other types if specified.",
+ "@function toObject",
+ "@memberof " + exportName(type),
+ "@static",
+ "@param {" + exportName(type) + "} " + (config.beautify ? "message" : "m") + " " + type.name,
+ "@param {$protobuf.IConversionOptions} [" + (config.beautify ? "options" : "o") + "] Conversion options",
+ "@returns {Object.<string,*>} Plain object"
+ ]);
+ buildFunction(type, "toObject", protobuf.converter.toObject(type));
+
+ push("");
+ pushComment([
+ "Converts this " + type.name + " to JSON.",
+ "@function toJSON",
+ "@memberof " + exportName(type),
+ "@instance",
+ "@returns {Object.<string,*>} JSON object"
+ ]);
+ push(escapeName(type.name) + ".prototype.toJSON = function toJSON() {");
+ ++indent;
+ push("return this.constructor.toObject(this, $protobuf.util.toJSONOptions);");
+ --indent;
+ push("};");
+ }
+}
+
+function buildService(ref, service) {
+
+ push("");
+ pushComment([
+ "Constructs a new " + service.name + " service.",
+ service.parent instanceof protobuf.Root ? "@exports " + escapeName(service.name) : "@memberof " + exportName(service.parent),
+ "@classdesc " + (service.comment || "Represents " + aOrAn(service.name)),
+ "@extends $protobuf.rpc.Service",
+ "@constructor",
+ "@param {$protobuf.RPCImpl} rpcImpl RPC implementation",
+ "@param {boolean} [requestDelimited=false] Whether requests are length-delimited",
+ "@param {boolean} [responseDelimited=false] Whether responses are length-delimited"
+ ]);
+ push("function " + escapeName(service.name) + "(rpcImpl, requestDelimited, responseDelimited) {");
+ ++indent;
+ push("$protobuf.rpc.Service.call(this, rpcImpl, requestDelimited, responseDelimited);");
+ --indent;
+ push("}");
+ push("");
+ push("(" + escapeName(service.name) + ".prototype = Object.create($protobuf.rpc.Service.prototype)).constructor = " + escapeName(service.name) + ";");
+
+ if (config.create) {
+ push("");
+ pushComment([
+ "Creates new " + service.name + " service using the specified rpc implementation.",
+ "@function create",
+ "@memberof " + exportName(service),
+ "@static",
+ "@param {$protobuf.RPCImpl} rpcImpl RPC implementation",
+ "@param {boolean} [requestDelimited=false] Whether requests are length-delimited",
+ "@param {boolean} [responseDelimited=false] Whether responses are length-delimited",
+ "@returns {" + escapeName(service.name) + "} RPC service. Useful where requests and/or responses are streamed."
+ ]);
+ push(escapeName(service.name) + ".create = function create(rpcImpl, requestDelimited, responseDelimited) {");
+ ++indent;
+ push("return new this(rpcImpl, requestDelimited, responseDelimited);");
+ --indent;
+ push("};");
+ }
+
+ service.methodsArray.forEach(function(method) {
+ method.resolve();
+ var lcName = protobuf.util.lcFirst(method.name),
+ cbName = escapeName(method.name + "Callback");
+ push("");
+ pushComment([
+ "Callback as used by {@link " + exportName(service) + "#" + escapeName(lcName) + "}.",
+ // This is a more specialized version of protobuf.rpc.ServiceCallback
+ "@memberof " + exportName(service),
+ "@typedef " + cbName,
+ "@type {function}",
+ "@param {Error|null} error Error, if any",
+ "@param {" + exportName(method.resolvedResponseType) + "} [response] " + method.resolvedResponseType.name
+ ]);
+ push("");
+ pushComment([
+ method.comment || "Calls " + method.name + ".",
+ "@function " + lcName,
+ "@memberof " + exportName(service),
+ "@instance",
+ "@param {" + exportName(method.resolvedRequestType, !config.forceMessage) + "} request " + method.resolvedRequestType.name + " message or plain object",
+ "@param {" + exportName(service) + "." + cbName + "} callback Node-style callback called with the error, if any, and " + method.resolvedResponseType.name,
+ "@returns {undefined}",
+ "@variation 1"
+ ]);
+ push("Object.defineProperty(" + escapeName(service.name) + ".prototype" + util.safeProp(lcName) + " = function " + escapeName(lcName) + "(request, callback) {");
+ ++indent;
+ push("return this.rpcCall(" + escapeName(lcName) + ", $root." + exportName(method.resolvedRequestType) + ", $root." + exportName(method.resolvedResponseType) + ", request, callback);");
+ --indent;
+ push("}, \"name\", { value: " + JSON.stringify(method.name) + " });");
+ if (config.comments)
+ push("");
+ pushComment([
+ method.comment || "Calls " + method.name + ".",
+ "@function " + lcName,
+ "@memberof " + exportName(service),
+ "@instance",
+ "@param {" + exportName(method.resolvedRequestType, !config.forceMessage) + "} request " + method.resolvedRequestType.name + " message or plain object",
+ "@returns {Promise<" + exportName(method.resolvedResponseType) + ">} Promise",
+ "@variation 2"
+ ]);
+ });
+}
+
+function buildEnum(ref, enm) {
+
+ push("");
+ var comment = [
+ enm.comment || enm.name + " enum.",
+ enm.parent instanceof protobuf.Root ? "@exports " + escapeName(enm.name) : "@name " + exportName(enm),
+ config.forceEnumString ? "@enum {string}" : "@enum {number}",
+ ];
+ Object.keys(enm.values).forEach(function(key) {
+ var val = config.forceEnumString ? key : enm.values[key];
+ comment.push((config.forceEnumString ? "@property {string} " : "@property {number} ") + key + "=" + val + " " + (enm.comments[key] || key + " value"));
+ });
+ pushComment(comment);
+ if (!ref && config.es6)
+ push("export const " + escapeName(enm.name) + " = " + escapeName(ref) + "." + escapeName(enm.name) + " = (() => {");
+ else
+ push(escapeName(ref) + "." + escapeName(enm.name) + " = (function() {");
+ ++indent;
+ push((config.es6 ? "const" : "var") + " valuesById = {}, values = Object.create(valuesById);");
+ var aliased = [];
+ Object.keys(enm.values).forEach(function(key) {
+ var valueId = enm.values[key];
+ var val = config.forceEnumString ? JSON.stringify(key) : valueId;
+ if (aliased.indexOf(valueId) > -1)
+ push("values[" + JSON.stringify(key) + "] = " + val + ";");
+ else {
+ push("values[valuesById[" + valueId + "] = " + JSON.stringify(key) + "] = " + val + ";");
+ aliased.push(valueId);
+ }
+ });
+ push("return values;");
+ --indent;
+ push("})();");
+}