No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

static.js 27KB

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