static.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  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) {
  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. return "Array.<" + type + ">";
  324. return type;
  325. }
  326. function buildType(ref, type) {
  327. if (config.comments) {
  328. var typeDef = [
  329. "Properties of " + aOrAn(type.name) + ".",
  330. type.parent instanceof protobuf.Root ? "@exports " + escapeName("I" + type.name) : "@memberof " + exportName(type.parent),
  331. "@interface " + escapeName("I" + type.name)
  332. ];
  333. type.fieldsArray.forEach(function(field) {
  334. var prop = util.safeProp(field.name); // either .name or ["name"]
  335. prop = prop.substring(1, prop.charAt(0) === "[" ? prop.length - 1 : prop.length);
  336. var jsType = toJsType(field);
  337. if (field.optional)
  338. jsType = jsType + "|null";
  339. typeDef.push("@property {" + jsType + "} " + (field.optional ? "[" + prop + "]" : prop) + " " + (field.comment || type.name + " " + field.name));
  340. });
  341. push("");
  342. pushComment(typeDef);
  343. }
  344. // constructor
  345. push("");
  346. pushComment([
  347. "Constructs a new " + type.name + ".",
  348. type.parent instanceof protobuf.Root ? "@exports " + escapeName(type.name) : "@memberof " + exportName(type.parent),
  349. "@classdesc " + (type.comment || "Represents " + aOrAn(type.name) + "."),
  350. config.comments ? "@implements " + escapeName("I" + type.name) : null,
  351. "@constructor",
  352. "@param {" + exportName(type, true) + "=} [" + (config.beautify ? "properties" : "p") + "] Properties to set"
  353. ]);
  354. buildFunction(type, type.name, Type.generateConstructor(type));
  355. // default values
  356. var firstField = true;
  357. type.fieldsArray.forEach(function(field) {
  358. field.resolve();
  359. var prop = util.safeProp(field.name);
  360. if (config.comments) {
  361. push("");
  362. var jsType = toJsType(field);
  363. if (field.optional && !field.map && !field.repeated && field.resolvedType instanceof Type)
  364. jsType = jsType + "|null|undefined";
  365. pushComment([
  366. field.comment || type.name + " " + field.name + ".",
  367. "@member {" + jsType + "} " + field.name,
  368. "@memberof " + exportName(type),
  369. "@instance"
  370. ]);
  371. } else if (firstField) {
  372. push("");
  373. firstField = false;
  374. }
  375. if (field.repeated)
  376. push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyArray;"); // overwritten in constructor
  377. else if (field.map)
  378. push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyObject;"); // overwritten in constructor
  379. else if (field.long)
  380. push(escapeName(type.name) + ".prototype" + prop + " = $util.Long ? $util.Long.fromBits("
  381. + JSON.stringify(field.typeDefault.low) + ","
  382. + JSON.stringify(field.typeDefault.high) + ","
  383. + JSON.stringify(field.typeDefault.unsigned)
  384. + ") : " + field.typeDefault.toNumber(field.type.charAt(0) === "u") + ";");
  385. else if (field.bytes) {
  386. push(escapeName(type.name) + ".prototype" + prop + " = $util.newBuffer(" + JSON.stringify(Array.prototype.slice.call(field.typeDefault)) + ");");
  387. } else
  388. push(escapeName(type.name) + ".prototype" + prop + " = " + JSON.stringify(field.typeDefault) + ";");
  389. });
  390. // virtual oneof fields
  391. var firstOneOf = true;
  392. type.oneofsArray.forEach(function(oneof) {
  393. if (firstOneOf) {
  394. firstOneOf = false;
  395. push("");
  396. if (config.comments)
  397. push("// OneOf field names bound to virtual getters and setters");
  398. push((config.es6 ? "let" : "var") + " $oneOfFields;");
  399. }
  400. oneof.resolve();
  401. push("");
  402. pushComment([
  403. oneof.comment || type.name + " " + oneof.name + ".",
  404. "@member {" + oneof.oneof.map(JSON.stringify).join("|") + "|undefined} " + escapeName(oneof.name),
  405. "@memberof " + exportName(type),
  406. "@instance"
  407. ]);
  408. push("Object.defineProperty(" + escapeName(type.name) + ".prototype, " + JSON.stringify(oneof.name) +", {");
  409. ++indent;
  410. push("get: $util.oneOfGetter($oneOfFields = [" + oneof.oneof.map(JSON.stringify).join(", ") + "]),");
  411. push("set: $util.oneOfSetter($oneOfFields)");
  412. --indent;
  413. push("});");
  414. });
  415. if (config.create) {
  416. push("");
  417. pushComment([
  418. "Creates a new " + type.name + " instance using the specified properties.",
  419. "@function create",
  420. "@memberof " + exportName(type),
  421. "@static",
  422. "@param {" + exportName(type, true) + "=} [properties] Properties to set",
  423. "@returns {" + exportName(type) + "} " + type.name + " instance"
  424. ]);
  425. push(escapeName(type.name) + ".create = function create(properties) {");
  426. ++indent;
  427. push("return new " + escapeName(type.name) + "(properties);");
  428. --indent;
  429. push("};");
  430. }
  431. if (config.encode) {
  432. push("");
  433. pushComment([
  434. "Encodes the specified " + type.name + " message. Does not implicitly {@link " + exportName(type) + ".verify|verify} messages.",
  435. "@function encode",
  436. "@memberof " + exportName(type),
  437. "@static",
  438. "@param {" + exportName(type, !config.forceMessage) + "} " + (config.beautify ? "message" : "m") + " " + type.name + " message or plain object to encode",
  439. "@param {$protobuf.Writer} [" + (config.beautify ? "writer" : "w") + "] Writer to encode to",
  440. "@returns {$protobuf.Writer} Writer"
  441. ]);
  442. buildFunction(type, "encode", protobuf.encoder(type));
  443. if (config.delimited) {
  444. push("");
  445. pushComment([
  446. "Encodes the specified " + type.name + " message, length delimited. Does not implicitly {@link " + exportName(type) + ".verify|verify} messages.",
  447. "@function encodeDelimited",
  448. "@memberof " + exportName(type),
  449. "@static",
  450. "@param {" + exportName(type, !config.forceMessage) + "} message " + type.name + " message or plain object to encode",
  451. "@param {$protobuf.Writer} [writer] Writer to encode to",
  452. "@returns {$protobuf.Writer} Writer"
  453. ]);
  454. push(escapeName(type.name) + ".encodeDelimited = function encodeDelimited(message, writer) {");
  455. ++indent;
  456. push("return this.encode(message, writer).ldelim();");
  457. --indent;
  458. push("};");
  459. }
  460. }
  461. if (config.decode) {
  462. push("");
  463. pushComment([
  464. "Decodes " + aOrAn(type.name) + " message from the specified reader or buffer.",
  465. "@function decode",
  466. "@memberof " + exportName(type),
  467. "@static",
  468. "@param {$protobuf.Reader|Uint8Array} " + (config.beautify ? "reader" : "r") + " Reader or buffer to decode from",
  469. "@param {number} [" + (config.beautify ? "length" : "l") + "] Message length if known beforehand",
  470. "@returns {" + exportName(type) + "} " + type.name,
  471. "@throws {Error} If the payload is not a reader or valid buffer",
  472. "@throws {$protobuf.util.ProtocolError} If required fields are missing"
  473. ]);
  474. buildFunction(type, "decode", protobuf.decoder(type));
  475. if (config.delimited) {
  476. push("");
  477. pushComment([
  478. "Decodes " + aOrAn(type.name) + " message from the specified reader or buffer, length delimited.",
  479. "@function decodeDelimited",
  480. "@memberof " + exportName(type),
  481. "@static",
  482. "@param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from",
  483. "@returns {" + exportName(type) + "} " + type.name,
  484. "@throws {Error} If the payload is not a reader or valid buffer",
  485. "@throws {$protobuf.util.ProtocolError} If required fields are missing"
  486. ]);
  487. push(escapeName(type.name) + ".decodeDelimited = function decodeDelimited(reader) {");
  488. ++indent;
  489. push("if (!(reader instanceof $Reader))");
  490. ++indent;
  491. push("reader = new $Reader(reader);");
  492. --indent;
  493. push("return this.decode(reader, reader.uint32());");
  494. --indent;
  495. push("};");
  496. }
  497. }
  498. if (config.verify) {
  499. push("");
  500. pushComment([
  501. "Verifies " + aOrAn(type.name) + " message.",
  502. "@function verify",
  503. "@memberof " + exportName(type),
  504. "@static",
  505. "@param {Object.<string,*>} " + (config.beautify ? "message" : "m") + " Plain object to verify",
  506. "@returns {string|null} `null` if valid, otherwise the reason why it is not"
  507. ]);
  508. buildFunction(type, "verify", protobuf.verifier(type));
  509. }
  510. if (config.convert) {
  511. push("");
  512. pushComment([
  513. "Creates " + aOrAn(type.name) + " message from a plain object. Also converts values to their respective internal types.",
  514. "@function fromObject",
  515. "@memberof " + exportName(type),
  516. "@static",
  517. "@param {Object.<string,*>} " + (config.beautify ? "object" : "d") + " Plain object",
  518. "@returns {" + exportName(type) + "} " + type.name
  519. ]);
  520. buildFunction(type, "fromObject", protobuf.converter.fromObject(type));
  521. push("");
  522. pushComment([
  523. "Creates a plain object from " + aOrAn(type.name) + " message. Also converts values to other types if specified.",
  524. "@function toObject",
  525. "@memberof " + exportName(type),
  526. "@static",
  527. "@param {" + exportName(type) + "} " + (config.beautify ? "message" : "m") + " " + type.name,
  528. "@param {$protobuf.IConversionOptions} [" + (config.beautify ? "options" : "o") + "] Conversion options",
  529. "@returns {Object.<string,*>} Plain object"
  530. ]);
  531. buildFunction(type, "toObject", protobuf.converter.toObject(type));
  532. push("");
  533. pushComment([
  534. "Converts this " + type.name + " to JSON.",
  535. "@function toJSON",
  536. "@memberof " + exportName(type),
  537. "@instance",
  538. "@returns {Object.<string,*>} JSON object"
  539. ]);
  540. push(escapeName(type.name) + ".prototype.toJSON = function toJSON() {");
  541. ++indent;
  542. push("return this.constructor.toObject(this, $protobuf.util.toJSONOptions);");
  543. --indent;
  544. push("};");
  545. }
  546. }
  547. function buildService(ref, service) {
  548. push("");
  549. pushComment([
  550. "Constructs a new " + service.name + " service.",
  551. service.parent instanceof protobuf.Root ? "@exports " + escapeName(service.name) : "@memberof " + exportName(service.parent),
  552. "@classdesc " + (service.comment || "Represents " + aOrAn(service.name)),
  553. "@extends $protobuf.rpc.Service",
  554. "@constructor",
  555. "@param {$protobuf.RPCImpl} rpcImpl RPC implementation",
  556. "@param {boolean} [requestDelimited=false] Whether requests are length-delimited",
  557. "@param {boolean} [responseDelimited=false] Whether responses are length-delimited"
  558. ]);
  559. push("function " + escapeName(service.name) + "(rpcImpl, requestDelimited, responseDelimited) {");
  560. ++indent;
  561. push("$protobuf.rpc.Service.call(this, rpcImpl, requestDelimited, responseDelimited);");
  562. --indent;
  563. push("}");
  564. push("");
  565. push("(" + escapeName(service.name) + ".prototype = Object.create($protobuf.rpc.Service.prototype)).constructor = " + escapeName(service.name) + ";");
  566. if (config.create) {
  567. push("");
  568. pushComment([
  569. "Creates new " + service.name + " service using the specified rpc implementation.",
  570. "@function create",
  571. "@memberof " + exportName(service),
  572. "@static",
  573. "@param {$protobuf.RPCImpl} rpcImpl RPC implementation",
  574. "@param {boolean} [requestDelimited=false] Whether requests are length-delimited",
  575. "@param {boolean} [responseDelimited=false] Whether responses are length-delimited",
  576. "@returns {" + escapeName(service.name) + "} RPC service. Useful where requests and/or responses are streamed."
  577. ]);
  578. push(escapeName(service.name) + ".create = function create(rpcImpl, requestDelimited, responseDelimited) {");
  579. ++indent;
  580. push("return new this(rpcImpl, requestDelimited, responseDelimited);");
  581. --indent;
  582. push("};");
  583. }
  584. service.methodsArray.forEach(function(method) {
  585. method.resolve();
  586. var lcName = protobuf.util.lcFirst(method.name),
  587. cbName = escapeName(method.name + "Callback");
  588. push("");
  589. pushComment([
  590. "Callback as used by {@link " + exportName(service) + "#" + escapeName(lcName) + "}.",
  591. // This is a more specialized version of protobuf.rpc.ServiceCallback
  592. "@memberof " + exportName(service),
  593. "@typedef " + cbName,
  594. "@type {function}",
  595. "@param {Error|null} error Error, if any",
  596. "@param {" + exportName(method.resolvedResponseType) + "} [response] " + method.resolvedResponseType.name
  597. ]);
  598. push("");
  599. pushComment([
  600. method.comment || "Calls " + method.name + ".",
  601. "@function " + lcName,
  602. "@memberof " + exportName(service),
  603. "@instance",
  604. "@param {" + exportName(method.resolvedRequestType, !config.forceMessage) + "} request " + method.resolvedRequestType.name + " message or plain object",
  605. "@param {" + exportName(service) + "." + cbName + "} callback Node-style callback called with the error, if any, and " + method.resolvedResponseType.name,
  606. "@returns {undefined}",
  607. "@variation 1"
  608. ]);
  609. push("Object.defineProperty(" + escapeName(service.name) + ".prototype" + util.safeProp(lcName) + " = function " + escapeName(lcName) + "(request, callback) {");
  610. ++indent;
  611. push("return this.rpcCall(" + escapeName(lcName) + ", $root." + exportName(method.resolvedRequestType) + ", $root." + exportName(method.resolvedResponseType) + ", request, callback);");
  612. --indent;
  613. push("}, \"name\", { value: " + JSON.stringify(method.name) + " });");
  614. if (config.comments)
  615. push("");
  616. pushComment([
  617. method.comment || "Calls " + method.name + ".",
  618. "@function " + lcName,
  619. "@memberof " + exportName(service),
  620. "@instance",
  621. "@param {" + exportName(method.resolvedRequestType, !config.forceMessage) + "} request " + method.resolvedRequestType.name + " message or plain object",
  622. "@returns {Promise<" + exportName(method.resolvedResponseType) + ">} Promise",
  623. "@variation 2"
  624. ]);
  625. });
  626. }
  627. function buildEnum(ref, enm) {
  628. push("");
  629. var comment = [
  630. enm.comment || enm.name + " enum.",
  631. enm.parent instanceof protobuf.Root ? "@exports " + escapeName(enm.name) : "@name " + exportName(enm),
  632. config.forceEnumString ? "@enum {number}" : "@enum {string}",
  633. ];
  634. Object.keys(enm.values).forEach(function(key) {
  635. var val = config.forceEnumString ? key : enm.values[key];
  636. comment.push((config.forceEnumString ? "@property {string} " : "@property {number} ") + key + "=" + val + " " + (enm.comments[key] || key + " value"));
  637. });
  638. pushComment(comment);
  639. push(escapeName(ref) + "." + escapeName(enm.name) + " = (function() {");
  640. ++indent;
  641. push((config.es6 ? "const" : "var") + " valuesById = {}, values = Object.create(valuesById);");
  642. var aliased = [];
  643. Object.keys(enm.values).forEach(function(key) {
  644. var valueId = enm.values[key];
  645. var val = config.forceEnumString ? JSON.stringify(key) : valueId;
  646. if (aliased.indexOf(valueId) > -1)
  647. push("values[" + JSON.stringify(key) + "] = " + val + ";");
  648. else {
  649. push("values[valuesById[" + valueId + "] = " + JSON.stringify(key) + "] = " + val + ";");
  650. aliased.push(valueId);
  651. }
  652. });
  653. push("return values;");
  654. --indent;
  655. push("})();");
  656. }