static.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. "use strict";
  2. module.exports = static_target;
  3. var protobuf = require("../.."),
  4. UglifyJS = require("uglify-js"),
  5. espree = require("espree"),
  6. escodegen = require("escodegen"),
  7. estraverse = require("estraverse");
  8. var Type = protobuf.Type,
  9. Service = protobuf.Service,
  10. Enum = protobuf.Enum,
  11. Namespace = protobuf.Namespace,
  12. util = protobuf.util;
  13. var out = [];
  14. var indent = 0;
  15. var config = {};
  16. static_target.description = "Static code without reflection (non-functional on its own)";
  17. function static_target(root, options, callback) {
  18. config = options;
  19. try {
  20. var aliases = [];
  21. if (config.decode)
  22. aliases.push("Reader");
  23. if (config.encode)
  24. aliases.push("Writer");
  25. aliases.push("util");
  26. if (aliases.length) {
  27. if (config.comments)
  28. push("// Common aliases");
  29. push((config.es6 ? "const " : "var ") + aliases.map(function(name) { return "$" + name + " = $protobuf." + name; }).join(", ") + ";");
  30. push("");
  31. }
  32. if (config.comments) {
  33. if (root.comment) {
  34. pushComment("@fileoverview " + root.comment);
  35. push("");
  36. }
  37. push("// Exported root namespace");
  38. }
  39. var rootProp = util.safeProp(config.root || "default");
  40. push((config.es6 ? "const" : "var") + " $root = $protobuf.roots" + rootProp + " || ($protobuf.roots" + rootProp + " = {});");
  41. buildNamespace(null, root);
  42. return callback(null, out.join("\n"));
  43. } catch (err) {
  44. return callback(err);
  45. } finally {
  46. out = [];
  47. indent = 0;
  48. config = {};
  49. }
  50. }
  51. function push(line) {
  52. if (line === "")
  53. return out.push("");
  54. var ind = "";
  55. for (var i = 0; i < indent; ++i)
  56. ind += " ";
  57. return out.push(ind + line);
  58. }
  59. function pushComment(lines) {
  60. if (!config.comments)
  61. return;
  62. var split = [];
  63. for (var i = 0; i < lines.length; ++i)
  64. if (lines[i] != null && lines[i].substring(0, 8) !== "@exclude")
  65. Array.prototype.push.apply(split, lines[i].split(/\r?\n/g));
  66. push("/**");
  67. split.forEach(function(line) {
  68. if (line === null)
  69. return;
  70. push(" * " + line.replace(/\*\//g, "* /"));
  71. });
  72. push(" */");
  73. }
  74. function exportName(object, asInterface) {
  75. if (asInterface) {
  76. if (object.__interfaceName)
  77. return object.__interfaceName;
  78. } else if (object.__exportName)
  79. return object.__exportName;
  80. var parts = object.fullName.substring(1).split("."),
  81. i = 0;
  82. while (i < parts.length)
  83. parts[i] = escapeName(parts[i++]);
  84. if (asInterface)
  85. parts[i - 1] = "I" + parts[i - 1];
  86. return object[asInterface ? "__interfaceName" : "__exportName"] = parts.join(".");
  87. }
  88. function escapeName(name) {
  89. if (!name)
  90. return "$root";
  91. return util.isReserved(name) ? name + "_" : name;
  92. }
  93. function aOrAn(name) {
  94. return ((/^[hH](?:ou|on|ei)/.test(name) || /^[aeiouAEIOU][a-z]/.test(name)) && !/^us/i.test(name)
  95. ? "an "
  96. : "a ") + name;
  97. }
  98. function buildNamespace(ref, ns) {
  99. if (!ns)
  100. return;
  101. if (ns.name !== "") {
  102. push("");
  103. if (!ref && config.es6)
  104. push("export const " + escapeName(ns.name) + " = " + escapeName(ref) + "." + escapeName(ns.name) + " = (() => {");
  105. else
  106. push(escapeName(ref) + "." + escapeName(ns.name) + " = (function() {");
  107. ++indent;
  108. }
  109. if (ns instanceof Type) {
  110. buildType(undefined, ns);
  111. } else if (ns instanceof Service)
  112. buildService(undefined, ns);
  113. else if (ns.name !== "") {
  114. push("");
  115. pushComment([
  116. ns.comment || "Namespace " + ns.name + ".",
  117. ns.parent instanceof protobuf.Root ? "@exports " + escapeName(ns.name) : "@memberof " + exportName(ns.parent),
  118. "@namespace"
  119. ]);
  120. push((config.es6 ? "const" : "var") + " " + escapeName(ns.name) + " = {};");
  121. }
  122. ns.nestedArray.forEach(function(nested) {
  123. if (nested instanceof Enum)
  124. buildEnum(ns.name, nested);
  125. else if (nested instanceof Namespace)
  126. buildNamespace(ns.name, nested);
  127. });
  128. if (ns.name !== "") {
  129. push("");
  130. push("return " + escapeName(ns.name) + ";");
  131. --indent;
  132. push("})();");
  133. }
  134. }
  135. var reduceableBlockStatements = {
  136. IfStatement: true,
  137. ForStatement: true,
  138. WhileStatement: true
  139. };
  140. var shortVars = {
  141. "r": "reader",
  142. "w": "writer",
  143. "m": "message",
  144. "t": "tag",
  145. "l": "length",
  146. "c": "end", "c2": "end2",
  147. "k": "key",
  148. "ks": "keys", "ks2": "keys2",
  149. "e": "error",
  150. "f": "impl",
  151. "o": "options",
  152. "d": "object",
  153. "n": "long",
  154. "p": "properties"
  155. };
  156. function beautifyCode(code) {
  157. // Add semicolons
  158. code = UglifyJS.minify(code, {
  159. compress: false,
  160. mangle: false,
  161. output: { beautify: true }
  162. }).code;
  163. // Properly beautify
  164. var ast = espree.parse(code);
  165. estraverse.replace(ast, {
  166. enter: function(node, parent) {
  167. // rename short vars
  168. if (node.type === "Identifier" && (parent.property !== node || parent.computed) && shortVars[node.name])
  169. return {
  170. "type": "Identifier",
  171. "name": shortVars[node.name]
  172. };
  173. // replace var with let if es6
  174. if (config.es6 && node.type === "VariableDeclaration" && node.kind === "var") {
  175. node.kind = "let";
  176. return undefined;
  177. }
  178. // remove braces around block statements with a single child
  179. if (node.type === "BlockStatement" && reduceableBlockStatements[parent.type] && node.body.length === 1)
  180. return node.body[0];
  181. return undefined;
  182. }
  183. });
  184. code = escodegen.generate(ast, {
  185. format: {
  186. newline: "\n",
  187. quotes: "double"
  188. }
  189. });
  190. // Add id, wireType comments
  191. if (config.comments)
  192. code = code.replace(/\.uint32\((\d+)\)/g, function($0, $1) {
  193. var id = $1 >>> 3,
  194. wireType = $1 & 7;
  195. return ".uint32(/* id " + id + ", wireType " + wireType + " =*/" + $1 + ")";
  196. });
  197. return code;
  198. }
  199. var renameVars = {
  200. "Writer": "$Writer",
  201. "Reader": "$Reader",
  202. "util": "$util"
  203. };
  204. function buildFunction(type, functionName, gen, scope) {
  205. var code = gen.toString(functionName)
  206. .replace(/((?!\.)types\[\d+])(\.values)/g, "$1"); // enums: use types[N] instead of reflected types[N].values
  207. var ast = espree.parse(code);
  208. /* eslint-disable no-extra-parens */
  209. estraverse.replace(ast, {
  210. enter: function(node, parent) {
  211. // rename vars
  212. if (
  213. node.type === "Identifier" && renameVars[node.name]
  214. && (
  215. (parent.type === "MemberExpression" && parent.object === node)
  216. || (parent.type === "BinaryExpression" && parent.right === node)
  217. )
  218. )
  219. return {
  220. "type": "Identifier",
  221. "name": renameVars[node.name]
  222. };
  223. // replace this.ctor with the actual ctor
  224. if (
  225. node.type === "MemberExpression"
  226. && node.object.type === "ThisExpression"
  227. && node.property.type === "Identifier" && node.property.name === "ctor"
  228. )
  229. return {
  230. "type": "Identifier",
  231. "name": "$root" + type.fullName
  232. };
  233. // replace types[N] with the field's actual type
  234. if (
  235. node.type === "MemberExpression"
  236. && node.object.type === "Identifier" && node.object.name === "types"
  237. && node.property.type === "Literal"
  238. )
  239. return {
  240. "type": "Identifier",
  241. "name": "$root" + type.fieldsArray[node.property.value].resolvedType.fullName
  242. };
  243. return undefined;
  244. }
  245. });
  246. /* eslint-enable no-extra-parens */
  247. code = escodegen.generate(ast, {
  248. format: {
  249. newline: "\n",
  250. quotes: "double"
  251. }
  252. });
  253. if (config.beautify)
  254. code = beautifyCode(code);
  255. code = code.replace(/ {4}/g, "\t");
  256. var hasScope = scope && Object.keys(scope).length,
  257. isCtor = functionName === type.name;
  258. if (hasScope) // remove unused scope vars
  259. Object.keys(scope).forEach(function(key) {
  260. if (!new RegExp("\\b(" + key + ")\\b", "g").test(code))
  261. delete scope[key];
  262. });
  263. var lines = code.split(/\n/g);
  264. if (isCtor) // constructor
  265. push(lines[0]);
  266. else if (hasScope) // enclose in an iife
  267. push(escapeName(type.name) + "." + escapeName(functionName) + " = (function(" + Object.keys(scope).map(escapeName).join(", ") + ") { return " + lines[0]);
  268. else
  269. push(escapeName(type.name) + "." + escapeName(functionName) + " = " + lines[0]);
  270. lines.slice(1, lines.length - 1).forEach(function(line) {
  271. var prev = indent;
  272. var i = 0;
  273. while (line.charAt(i++) === "\t")
  274. ++indent;
  275. push(line.trim());
  276. indent = prev;
  277. });
  278. if (isCtor)
  279. push("}");
  280. else if (hasScope)
  281. push("};})(" + Object.keys(scope).map(function(key) { return scope[key]; }).join(", ") + ");");
  282. else
  283. push("};");
  284. }
  285. function toJsType(field, forInterface) {
  286. var type;
  287. switch (field.type) {
  288. case "double":
  289. case "float":
  290. case "int32":
  291. case "uint32":
  292. case "sint32":
  293. case "fixed32":
  294. case "sfixed32":
  295. type = "number";
  296. break;
  297. case "int64":
  298. case "uint64":
  299. case "sint64":
  300. case "fixed64":
  301. case "sfixed64":
  302. type = config.forceLong ? "Long" : config.forceNumber ? "number" : "number|Long";
  303. break;
  304. case "bool":
  305. type = "boolean";
  306. break;
  307. case "string":
  308. type = "string";
  309. break;
  310. case "bytes":
  311. type = "Uint8Array";
  312. break;
  313. default:
  314. if (field.resolve().resolvedType)
  315. type = exportName(field.resolvedType, !(field.resolvedType instanceof protobuf.Enum || config.forceMessage));
  316. else
  317. type = "*"; // should not happen
  318. break;
  319. }
  320. if (field.map)
  321. return "Object.<string," + type + ">";
  322. if (field.repeated) {
  323. var fullType = field.preEncoded() ? type + "|Uint8Array" : type;
  324. if (forInterface && field.useToArray()) {
  325. return "$protobuf.ToArray.<" + fullType + ">|Array.<" + fullType + ">";
  326. }
  327. return "Array.<" + fullType + ">";
  328. }
  329. return type;
  330. }
  331. function buildType(ref, type) {
  332. if (config.comments) {
  333. var typeDef = [
  334. "Properties of " + aOrAn(type.name) + ".",
  335. type.parent instanceof protobuf.Root ? "@exports " + escapeName("I" + type.name) : "@memberof " + exportName(type.parent),
  336. "@interface " + escapeName("I" + type.name)
  337. ];
  338. type.fieldsArray.forEach(function(field) {
  339. var prop = util.safeProp(field.name); // either .name or ["name"]
  340. prop = prop.substring(1, prop.charAt(0) === "[" ? prop.length - 1 : prop.length);
  341. var jsType = toJsType(field, true);
  342. if (field.optional)
  343. jsType = jsType + "|null";
  344. typeDef.push("@property {" + jsType + "} " + (field.optional ? "[" + prop + "]" : prop) + " " + (field.comment || type.name + " " + field.name));
  345. });
  346. push("");
  347. pushComment(typeDef);
  348. }
  349. // constructor
  350. push("");
  351. pushComment([
  352. "Constructs a new " + type.name + ".",
  353. type.parent instanceof protobuf.Root ? "@exports " + escapeName(type.name) : "@memberof " + exportName(type.parent),
  354. "@classdesc " + (type.comment || "Represents " + aOrAn(type.name) + "."),
  355. config.comments ? "@implements " + escapeName("I" + type.name) : null,
  356. "@constructor",
  357. "@param {" + exportName(type, true) + "=} [" + (config.beautify ? "properties" : "p") + "] Properties to set"
  358. ]);
  359. buildFunction(type, type.name, Type.generateConstructor(type));
  360. // default values
  361. var firstField = true;
  362. type.fieldsArray.forEach(function(field) {
  363. field.resolve();
  364. var prop = util.safeProp(field.name);
  365. if (config.comments) {
  366. push("");
  367. var jsType = toJsType(field, false);
  368. if (field.optional && !field.map && !field.repeated && field.resolvedType instanceof Type)
  369. jsType = jsType + "|null|undefined";
  370. pushComment([
  371. field.comment || type.name + " " + field.name + ".",
  372. "@member {" + jsType + "} " + field.name,
  373. "@memberof " + exportName(type),
  374. "@instance"
  375. ]);
  376. } else if (firstField) {
  377. push("");
  378. firstField = false;
  379. }
  380. if (field.repeated)
  381. push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyArray;"); // overwritten in constructor
  382. else if (field.map)
  383. push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyObject;"); // overwritten in constructor
  384. else if (field.long)
  385. push(escapeName(type.name) + ".prototype" + prop + " = $util.Long ? $util.Long.fromBits("
  386. + JSON.stringify(field.typeDefault.low) + ","
  387. + JSON.stringify(field.typeDefault.high) + ","
  388. + JSON.stringify(field.typeDefault.unsigned)
  389. + ") : " + field.typeDefault.toNumber(field.type.charAt(0) === "u") + ";");
  390. else if (field.bytes) {
  391. push(escapeName(type.name) + ".prototype" + prop + " = $util.newBuffer(" + JSON.stringify(Array.prototype.slice.call(field.typeDefault)) + ");");
  392. } else
  393. push(escapeName(type.name) + ".prototype" + prop + " = " + JSON.stringify(field.typeDefault) + ";");
  394. });
  395. // virtual oneof fields
  396. var firstOneOf = true;
  397. type.oneofsArray.forEach(function(oneof) {
  398. if (firstOneOf) {
  399. firstOneOf = false;
  400. push("");
  401. if (config.comments)
  402. push("// OneOf field names bound to virtual getters and setters");
  403. push((config.es6 ? "let" : "var") + " $oneOfFields;");
  404. }
  405. oneof.resolve();
  406. push("");
  407. pushComment([
  408. oneof.comment || type.name + " " + oneof.name + ".",
  409. "@member {" + oneof.oneof.map(JSON.stringify).join("|") + "|undefined} " + escapeName(oneof.name),
  410. "@memberof " + exportName(type),
  411. "@instance"
  412. ]);
  413. push("Object.defineProperty(" + escapeName(type.name) + ".prototype, " + JSON.stringify(oneof.name) +", {");
  414. ++indent;
  415. push("get: $util.oneOfGetter($oneOfFields = [" + oneof.oneof.map(JSON.stringify).join(", ") + "]),");
  416. push("set: $util.oneOfSetter($oneOfFields)");
  417. --indent;
  418. push("});");
  419. });
  420. if (config.create) {
  421. push("");
  422. pushComment([
  423. "Creates a new " + type.name + " instance using the specified properties.",
  424. "@function create",
  425. "@memberof " + exportName(type),
  426. "@static",
  427. "@param {" + exportName(type, true) + "=} [properties] Properties to set",
  428. "@returns {" + exportName(type) + "} " + type.name + " instance"
  429. ]);
  430. push(escapeName(type.name) + ".create = function create(properties) {");
  431. ++indent;
  432. push("return new " + escapeName(type.name) + "(properties);");
  433. --indent;
  434. push("};");
  435. }
  436. if (config.encode) {
  437. push("");
  438. pushComment([
  439. "Encodes the specified " + type.name + " message. Does not implicitly {@link " + exportName(type) + ".verify|verify} messages.",
  440. "@function encode",
  441. "@memberof " + exportName(type),
  442. "@static",
  443. "@param {" + exportName(type, !config.forceMessage) + "} " + (config.beautify ? "message" : "m") + " " + type.name + " message or plain object to encode",
  444. "@param {$protobuf.Writer} [" + (config.beautify ? "writer" : "w") + "] Writer to encode to",
  445. "@returns {$protobuf.Writer} Writer"
  446. ]);
  447. buildFunction(type, "encode", protobuf.encoder(type));
  448. if (config.delimited) {
  449. push("");
  450. pushComment([
  451. "Encodes the specified " + type.name + " message, length delimited. Does not implicitly {@link " + exportName(type) + ".verify|verify} messages.",
  452. "@function encodeDelimited",
  453. "@memberof " + exportName(type),
  454. "@static",
  455. "@param {" + exportName(type, !config.forceMessage) + "} message " + type.name + " message or plain object to encode",
  456. "@param {$protobuf.Writer} [writer] Writer to encode to",
  457. "@returns {$protobuf.Writer} Writer"
  458. ]);
  459. push(escapeName(type.name) + ".encodeDelimited = function encodeDelimited(message, writer) {");
  460. ++indent;
  461. push("return this.encode(message, writer).ldelim();");
  462. --indent;
  463. push("};");
  464. }
  465. }
  466. if (config.decode) {
  467. push("");
  468. pushComment([
  469. "Decodes " + aOrAn(type.name) + " message from the specified reader or buffer.",
  470. "@function decode",
  471. "@memberof " + exportName(type),
  472. "@static",
  473. "@param {$protobuf.Reader|Uint8Array} " + (config.beautify ? "reader" : "r") + " Reader or buffer to decode from",
  474. "@param {number} [" + (config.beautify ? "length" : "l") + "] Message length if known beforehand",
  475. "@returns {" + exportName(type) + "} " + type.name,
  476. "@throws {Error} If the payload is not a reader or valid buffer",
  477. "@throws {$protobuf.util.ProtocolError} If required fields are missing"
  478. ]);
  479. buildFunction(type, "decode", protobuf.decoder(type));
  480. if (config.delimited) {
  481. push("");
  482. pushComment([
  483. "Decodes " + aOrAn(type.name) + " message from the specified reader or buffer, length delimited.",
  484. "@function decodeDelimited",
  485. "@memberof " + exportName(type),
  486. "@static",
  487. "@param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from",
  488. "@returns {" + exportName(type) + "} " + type.name,
  489. "@throws {Error} If the payload is not a reader or valid buffer",
  490. "@throws {$protobuf.util.ProtocolError} If required fields are missing"
  491. ]);
  492. push(escapeName(type.name) + ".decodeDelimited = function decodeDelimited(reader) {");
  493. ++indent;
  494. push("if (!(reader instanceof $Reader))");
  495. ++indent;
  496. push("reader = new $Reader(reader);");
  497. --indent;
  498. push("return this.decode(reader, reader.uint32());");
  499. --indent;
  500. push("};");
  501. }
  502. }
  503. if (config.verify) {
  504. push("");
  505. pushComment([
  506. "Verifies " + aOrAn(type.name) + " message.",
  507. "@function verify",
  508. "@memberof " + exportName(type),
  509. "@static",
  510. "@param {Object.<string,*>} " + (config.beautify ? "message" : "m") + " Plain object to verify",
  511. "@returns {string|null} `null` if valid, otherwise the reason why it is not"
  512. ]);
  513. buildFunction(type, "verify", protobuf.verifier(type));
  514. }
  515. if (config.convert) {
  516. if (config.fromObject) {
  517. push("");
  518. pushComment([
  519. "Creates " + aOrAn(type.name) + " message from a plain object. Also converts values to their respective internal types.",
  520. "@function fromObject",
  521. "@memberof " + exportName(type),
  522. "@static",
  523. "@param {Object.<string,*>} " + (config.beautify ? "object" : "d") + " Plain object",
  524. "@returns {" + exportName(type) + "} " + type.name
  525. ]);
  526. buildFunction(type, "fromObject", protobuf.converter.fromObject(type));
  527. }
  528. push("");
  529. pushComment([
  530. "Creates a plain object from " + aOrAn(type.name) + " message. Also converts values to other types if specified.",
  531. "@function toObject",
  532. "@memberof " + exportName(type),
  533. "@static",
  534. "@param {" + exportName(type) + "} " + (config.beautify ? "message" : "m") + " " + type.name,
  535. "@param {$protobuf.IConversionOptions} [" + (config.beautify ? "options" : "o") + "] Conversion options",
  536. "@returns {Object.<string,*>} Plain object"
  537. ]);
  538. buildFunction(type, "toObject", protobuf.converter.toObject(type));
  539. push("");
  540. pushComment([
  541. "Converts this " + type.name + " to JSON.",
  542. "@function toJSON",
  543. "@memberof " + exportName(type),
  544. "@instance",
  545. "@returns {Object.<string,*>} JSON object"
  546. ]);
  547. push(escapeName(type.name) + ".prototype.toJSON = function toJSON() {");
  548. ++indent;
  549. push("return this.constructor.toObject(this, $protobuf.util.toJSONOptions);");
  550. --indent;
  551. push("};");
  552. }
  553. }
  554. function buildService(ref, service) {
  555. push("");
  556. pushComment([
  557. "Constructs a new " + service.name + " service.",
  558. service.parent instanceof protobuf.Root ? "@exports " + escapeName(service.name) : "@memberof " + exportName(service.parent),
  559. "@classdesc " + (service.comment || "Represents " + aOrAn(service.name)),
  560. "@extends $protobuf.rpc.Service",
  561. "@constructor",
  562. "@param {$protobuf.RPCImpl} rpcImpl RPC implementation",
  563. "@param {boolean} [requestDelimited=false] Whether requests are length-delimited",
  564. "@param {boolean} [responseDelimited=false] Whether responses are length-delimited"
  565. ]);
  566. push("function " + escapeName(service.name) + "(rpcImpl, requestDelimited, responseDelimited) {");
  567. ++indent;
  568. push("$protobuf.rpc.Service.call(this, rpcImpl, requestDelimited, responseDelimited);");
  569. --indent;
  570. push("}");
  571. push("");
  572. push("(" + escapeName(service.name) + ".prototype = Object.create($protobuf.rpc.Service.prototype)).constructor = " + escapeName(service.name) + ";");
  573. if (config.create) {
  574. push("");
  575. pushComment([
  576. "Creates new " + service.name + " service using the specified rpc implementation.",
  577. "@function create",
  578. "@memberof " + exportName(service),
  579. "@static",
  580. "@param {$protobuf.RPCImpl} rpcImpl RPC implementation",
  581. "@param {boolean} [requestDelimited=false] Whether requests are length-delimited",
  582. "@param {boolean} [responseDelimited=false] Whether responses are length-delimited",
  583. "@returns {" + escapeName(service.name) + "} RPC service. Useful where requests and/or responses are streamed."
  584. ]);
  585. push(escapeName(service.name) + ".create = function create(rpcImpl, requestDelimited, responseDelimited) {");
  586. ++indent;
  587. push("return new this(rpcImpl, requestDelimited, responseDelimited);");
  588. --indent;
  589. push("};");
  590. }
  591. service.methodsArray.forEach(function(method) {
  592. method.resolve();
  593. var lcName = protobuf.util.lcFirst(method.name),
  594. cbName = escapeName(method.name + "Callback");
  595. push("");
  596. pushComment([
  597. "Callback as used by {@link " + exportName(service) + "#" + escapeName(lcName) + "}.",
  598. // This is a more specialized version of protobuf.rpc.ServiceCallback
  599. "@memberof " + exportName(service),
  600. "@typedef " + cbName,
  601. "@type {function}",
  602. "@param {Error|null} error Error, if any",
  603. "@param {" + exportName(method.resolvedResponseType) + "} [response] " + method.resolvedResponseType.name
  604. ]);
  605. push("");
  606. pushComment([
  607. method.comment || "Calls " + method.name + ".",
  608. "@function " + lcName,
  609. "@memberof " + exportName(service),
  610. "@instance",
  611. "@param {" + exportName(method.resolvedRequestType, !config.forceMessage) + "} request " + method.resolvedRequestType.name + " message or plain object",
  612. "@param {" + exportName(service) + "." + cbName + "} callback Node-style callback called with the error, if any, and " + method.resolvedResponseType.name,
  613. "@returns {undefined}",
  614. "@variation 1"
  615. ]);
  616. push("Object.defineProperty(" + escapeName(service.name) + ".prototype" + util.safeProp(lcName) + " = function " + escapeName(lcName) + "(request, callback) {");
  617. ++indent;
  618. push("return this.rpcCall(" + escapeName(lcName) + ", $root." + exportName(method.resolvedRequestType) + ", $root." + exportName(method.resolvedResponseType) + ", request, callback);");
  619. --indent;
  620. push("}, \"name\", { value: " + JSON.stringify(method.name) + " });");
  621. if (config.comments)
  622. push("");
  623. pushComment([
  624. method.comment || "Calls " + method.name + ".",
  625. "@function " + lcName,
  626. "@memberof " + exportName(service),
  627. "@instance",
  628. "@param {" + exportName(method.resolvedRequestType, !config.forceMessage) + "} request " + method.resolvedRequestType.name + " message or plain object",
  629. "@returns {Promise<" + exportName(method.resolvedResponseType) + ">} Promise",
  630. "@variation 2"
  631. ]);
  632. });
  633. }
  634. function buildEnum(ref, enm) {
  635. push("");
  636. var comment = [
  637. enm.comment || enm.name + " enum.",
  638. enm.parent instanceof protobuf.Root ? "@exports " + escapeName(enm.name) : "@name " + exportName(enm),
  639. config.forceEnumString ? "@enum {number}" : "@enum {string}",
  640. ];
  641. Object.keys(enm.values).forEach(function(key) {
  642. var val = config.forceEnumString ? key : enm.values[key];
  643. comment.push((config.forceEnumString ? "@property {string} " : "@property {number} ") + key + "=" + val + " " + (enm.comments[key] || key + " value"));
  644. });
  645. pushComment(comment);
  646. push(escapeName(ref) + "." + escapeName(enm.name) + " = (function() {");
  647. ++indent;
  648. push((config.es6 ? "const" : "var") + " valuesById = {}, values = Object.create(valuesById);");
  649. var aliased = [];
  650. Object.keys(enm.values).forEach(function(key) {
  651. var valueId = enm.values[key];
  652. var val = config.forceEnumString ? JSON.stringify(key) : valueId;
  653. if (aliased.indexOf(valueId) > -1)
  654. push("values[" + JSON.stringify(key) + "] = " + val + ";");
  655. else {
  656. push("values[valuesById[" + valueId + "] = " + JSON.stringify(key) + "] = " + val + ";");
  657. aliased.push(valueId);
  658. }
  659. });
  660. push("return values;");
  661. --indent;
  662. push("})();");
  663. }