protobufjs 8.5.0 → 8.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,10 +10,10 @@ declare module ".." {
10
10
  }
11
11
 
12
12
  interface Type {
13
- /** Parses this type from protobuf text format. */
13
+ /** Installed by `textformat.install()`. Parses this type from protobuf text format. */
14
14
  fromText(text: string): $protobuf.Message<{}>;
15
15
 
16
- /** Formats a message of this type as protobuf text format. */
16
+ /** Installed by `textformat.install()`. Formats a message of this type as protobuf text format. */
17
17
  toText(message: ($protobuf.Message<{}>|{ [k: string]: any }), options?: ITextFormatOptions): string;
18
18
  }
19
19
  }
@@ -1,5 +1,7 @@
1
1
  // DO NOT EDIT! This is a generated file. Edit the source file instead and regenerate.
2
2
 
3
+ import * as $protobuf from "..";
4
+
3
5
  /** Maximum recursion depth for formatting length-delimited unknown fields. */
4
6
  export let unknownRecursionLimit: number;
5
7
 
@@ -9,3 +11,23 @@ export interface ITextFormatOptions {
9
11
  /** Also includes and formats unknown fields. */
10
12
  unknowns?: boolean;
11
13
  }
14
+
15
+ /**
16
+ * Parses a message from protobuf text format using the specified reflected type.
17
+ * @param type Reflected message type
18
+ * @param text Text format input
19
+ * @returns Message instance
20
+ */
21
+ export function fromText(type: $protobuf.Type, text: string): $protobuf.Message<{}>;
22
+
23
+ /**
24
+ * Formats a message as protobuf text format using the specified reflected type.
25
+ * @param type Reflected message type
26
+ * @param message Message instance or plain object
27
+ * @param [options] Text format options
28
+ * @returns Text format output
29
+ */
30
+ export function toText(type: $protobuf.Type, message: ($protobuf.Message<{}>|{ [k: string]: any }), options?: ITextFormatOptions): string;
31
+
32
+ /** Installs reflected {@link Type} convenience methods. */
33
+ export function install(): void;
package/ext/textformat.js CHANGED
@@ -68,40 +68,61 @@ function parseText(type, text) {
68
68
  * @property {boolean} [unknowns=false] Also includes and formats unknown fields.
69
69
  */
70
70
 
71
+ /**
72
+ * Parses a message from protobuf text format using the specified reflected type.
73
+ * @function fromText
74
+ * @name fromText
75
+ * @param {$protobuf.Type} type Reflected message type
76
+ * @param {string} text Text format input
77
+ * @returns {$protobuf.Message<{}>} Message instance
78
+ */
79
+ textformat.fromText = function fromText(type, text) {
80
+ return parseText(type, text);
81
+ };
82
+
71
83
  /**
72
84
  * Formats a message as protobuf text format using the specified reflected type.
73
- * @param {Type} type Reflected message type
74
- * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
85
+ * @function toText
86
+ * @name toText
87
+ * @param {$protobuf.Type} type Reflected message type
88
+ * @param {$protobuf.Message<{}>|Object.<string,*>} message Message instance or plain object
75
89
  * @param {ITextFormatOptions} [options] Text format options
76
90
  * @returns {string} Text format output
77
- * @private
78
91
  */
79
- function formatText(type, message, options) {
92
+ textformat.toText = function toText(type, message, options) {
80
93
  if (!(type instanceof Type))
81
94
  throw TypeError("type must be a Type");
82
95
  type.root.resolveAll();
83
96
  var lines = [];
84
97
  writeMessage(type, message, lines, 0, options || {}, 0);
85
98
  return lines.join("\n");
86
- }
87
-
88
- /**
89
- * Parses this type from protobuf text format.
90
- * @param {string} text Text format input
91
- * @returns {Message<{}>} Message instance
92
- */
93
- Type.prototype.fromText = function fromText(text) {
94
- return parseText(this, text);
95
99
  };
96
100
 
97
101
  /**
98
- * Formats a message of this type as protobuf text format.
99
- * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
100
- * @param {ITextFormatOptions} [options] Text format options
101
- * @returns {string} Text format output
102
+ * Installs reflected {@link Type} convenience methods.
103
+ * @function install
104
+ * @name install
105
+ * @returns {undefined}
102
106
  */
103
- Type.prototype.toText = function toText(message, options) {
104
- return formatText(this, message, options);
107
+ textformat.install = function install() {
108
+ /**
109
+ * Parses a message of this type from protobuf text format. Convenience for {@link textformat.fromText}.
110
+ * @param {string} text Text format input
111
+ * @returns {Message<{}>} Message instance
112
+ */
113
+ Type.prototype.fromText = function fromText(text) {
114
+ return textformat.fromText(this, text);
115
+ };
116
+
117
+ /**
118
+ * Formats a message of this type as protobuf text format. Convenience for {@link textformat.toText}.
119
+ * @param {Message<{}>|Object.<string,*>} message Message instance or plain object
120
+ * @param {ITextFormatOptions} [options] Text format options
121
+ * @returns {string} Text format output
122
+ */
123
+ Type.prototype.toText = function toText(message, options) {
124
+ return textformat.toText(this, message, options);
125
+ };
105
126
  };
106
127
 
107
128
  function Tokenizer(source) {
package/index.d.ts CHANGED
@@ -313,6 +313,18 @@ export class Field extends FieldBase {
313
313
  /** Determines whether this field tracks presence. */
314
314
  readonly hasPresence: boolean;
315
315
 
316
+ /**
317
+ * The field name as declared in the .proto source (snake_case). Populated on resolve,
318
+ * falling back to `name`. Mirrors `FieldDescriptorProto.name`.
319
+ */
320
+ readonly protoName: string;
321
+
322
+ /**
323
+ * The JSON name of this field (lowerCamelCase per protoc's `ToJsonName`, or an
324
+ * explicit `[json_name]`). Populated on resolve. This is the key used on ProtoJSON output.
325
+ */
326
+ readonly jsonName: string;
327
+
316
328
  /**
317
329
  * Field decorator (TypeScript).
318
330
  * @param fieldId Field id
@@ -388,6 +400,12 @@ export class FieldBase extends ReflectionObject {
388
400
  /** Comment for this field. */
389
401
  comment: (string|null);
390
402
 
403
+ /** Field name as declared in the .proto source, if different from `name`. */
404
+ protoName?: string;
405
+
406
+ /** JSON name, if different from the derived default. */
407
+ jsonName?: string;
408
+
391
409
  /**
392
410
  * Converts this field to a field descriptor.
393
411
  * @param [toJSONOptions] JSON conversion options
@@ -1464,15 +1482,15 @@ export namespace rpc {
1464
1482
 
1465
1483
  /** A service method part of a {@link rpc.Service} as created by {@link Service.create}. */
1466
1484
  type ServiceMethod<TReq extends Message<TReq>, TRes extends Message<TRes>> = {
1467
- (request: TReq|Properties<TReq>, callback: rpc.ServiceMethodCallback<TRes>): void;
1468
- (request: TReq|Properties<TReq>): Promise<TRes>;
1469
- readonly name: string;
1470
- readonly path: string;
1471
- readonly requestType: string;
1472
- readonly responseType: string;
1473
- readonly requestStream: true|undefined;
1474
- readonly responseStream: true|undefined;
1475
- };
1485
+ (request: TReq|Properties<TReq>, callback: rpc.ServiceMethodCallback<TRes>): void;
1486
+ (request: TReq|Properties<TReq>): Promise<TRes>;
1487
+ readonly name: string;
1488
+ readonly path: string;
1489
+ readonly requestType: string;
1490
+ readonly responseType: string;
1491
+ readonly requestStream: true|undefined;
1492
+ readonly responseStream: true|undefined;
1493
+ };
1476
1494
 
1477
1495
  /** An RPC service as returned by {@link Service#create}. */
1478
1496
  class Service extends util.EventEmitter {
@@ -2285,14 +2303,6 @@ export namespace util {
2285
2303
  function readDoubleBE(buf: Uint8Array, pos: number): number;
2286
2304
  }
2287
2305
 
2288
- /**
2289
- * Requires a module only if available.
2290
- * @param moduleName Module to require
2291
- * @returns Required module if available and not empty, otherwise `null`
2292
- * @deprecated Legacy optional require helper. Will be removed in a future release.
2293
- */
2294
- function inquire(moduleName: string): object;
2295
-
2296
2306
  /** Helper class for working with the low and high bits of a 64 bit value. */
2297
2307
  class LongBits {
2298
2308
 
@@ -2675,9 +2685,17 @@ export namespace util {
2675
2685
  * Converts a string to camel case.
2676
2686
  * @param str String to convert
2677
2687
  * @returns Converted string
2688
+ * @deprecated Use {@link util.jsonName} for protobuf field JSON names.
2678
2689
  */
2679
2690
  function camelCase(str: string): string;
2680
2691
 
2692
+ /**
2693
+ * Converts a proto field name to its protoc-compatible JSON name.
2694
+ * @param str Proto field name
2695
+ * @returns JSON name
2696
+ */
2697
+ function jsonName(str: string): string;
2698
+
2681
2699
  /**
2682
2700
  * Compares reflected fields by id.
2683
2701
  * @param a First field
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "protobufjs",
3
- "version": "8.5.0",
4
- "versionScheme": "~",
3
+ "version": "8.6.1",
5
4
  "description": "Protocol Buffers for JavaScript & TypeScript.",
6
5
  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
7
6
  "license": "BSD-3-Clause",
@@ -27,7 +26,7 @@
27
26
  "build": "npm run build:bundle && npm run build:types",
28
27
  "build:bundle": "gulp --gulpfile scripts/gulpfile.js",
29
28
  "build:tests": "node ./scripts/gentests.js",
30
- "build:types": "node cli/bin/pbts --main --global protobuf --out index.d.ts src/ && node cli/bin/pbts --main --import \"\\$protobuf=..\" --out ext/descriptor.generated.d.ts ext/descriptor.js && node cli/bin/pbts --main --out ext/textformat.generated.d.ts ext/textformat.js",
29
+ "build:types": "node cli/bin/pbts --main --global protobuf --out index.d.ts src/ && node cli/bin/pbts --main --import \"\\$protobuf=..\" --out ext/descriptor.generated.d.ts ext/descriptor.js && node cli/bin/pbts --main --import \"\\$protobuf=..\" --out ext/textformat.generated.d.ts ext/textformat.js && node cli/bin/pbts --main --import \"\\$protobuf=..\" --out ext/protojson.generated.d.ts ext/protojson.js",
31
30
  "coverage": "npm run coverage:test && npm run coverage:report",
32
31
  "coverage:test": "nyc --silent tape -r ./lib/tape-adapter tests/*.js tests/node/*.js",
33
32
  "coverage:report": "nyc report --reporter=lcov --reporter=text",
@@ -39,7 +38,6 @@
39
38
  "lint:types": "tslint \"**/*.d.ts\" -e \"**/node_modules/**\" -t stylish -c config/tslint.json",
40
39
  "prepublish": "cd cli && npm install && cd .. && npm run build",
41
40
  "prepublishOnly": "cd cli && npm install && cd .. && npm run build",
42
- "postinstall": "node scripts/postinstall",
43
41
  "prof": "node bench/prof",
44
42
  "test": "npm run test:sources && npm run test:types",
45
43
  "test:sources": "tape -r ./lib/tape-adapter tests/*.js tests/node/*.js",
@@ -74,7 +72,6 @@
74
72
  "tape": "^5.0.0",
75
73
  "tslint": "^6.0.0",
76
74
  "typescript": "^3.7.5",
77
- "uglify-js": "^3.7.7",
78
75
  "vinyl-buffer": "^1.0.1",
79
76
  "vinyl-fs": "^4.0.0",
80
77
  "vinyl-source-stream": "^2.0.0"
@@ -88,7 +85,6 @@
88
85
  "minimal.js",
89
86
  "package-lock.json",
90
87
  "tsconfig.json",
91
- "scripts/postinstall.js",
92
88
  "dist/**",
93
89
  "ext/**",
94
90
  "google/**",
package/src/converter.js CHANGED
@@ -106,7 +106,7 @@ function genValuePartial_fromObject(gen, field, fieldIndex, prop) {
106
106
  converter.fromObject = function fromObject(mtype) {
107
107
  /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
108
108
  var fields = mtype.fieldsArray;
109
- var gen = util.codegen(["d", "q"], mtype.name + "$fromObject")
109
+ var gen = util.codegen(["d", "q"])
110
110
  ("if(d instanceof C)")
111
111
  ("return d")
112
112
  ("if(!util.isObject(d))")
@@ -240,7 +240,7 @@ converter.toObject = function toObject(mtype) {
240
240
  var fields = mtype.fieldsArray.slice().sort(util.compareFieldsById);
241
241
  if (!fields.length)
242
242
  return util.codegen()("return {}");
243
- var gen = util.codegen(["m", "o", "q"], mtype.name + "$toObject")
243
+ var gen = util.codegen(["m", "o", "q"])
244
244
  ("if(!o)")
245
245
  ("o={}")
246
246
  ("if(q===undefined)q=0")
@@ -329,7 +329,7 @@ converter.toObject = function toObject(mtype) {
329
329
  genValuePartial_toObject(gen, field, /* sorted */ index, prop + "[j]")
330
330
  ("}");
331
331
  } else { gen
332
- ("if(m%s!=null&&m.hasOwnProperty(%j)){", prop, field.name); // !== undefined && !== null
332
+ ("if(m%s!=null&&Object.hasOwnProperty.call(m,%j)){", prop, field.name); // !== undefined && !== null
333
333
  genValuePartial_toObject(gen, field, /* sorted */ index, prop);
334
334
  if (field.partOf && !field.partOf.isProto3Optional) gen
335
335
  ("if(o.oneofs)")
package/src/decoder.js CHANGED
@@ -26,7 +26,7 @@ function decoder(mtype) {
26
26
  if (!pfield.repeated && !pfield.map && !pfield.hasPresence)
27
27
  hasImplicitPresenceField = true;
28
28
  }
29
- var gen = util.codegen(["r", "l", "z", "q", "g"], mtype.name + "$decode")
29
+ var gen = util.codegen(["r", "l", "z", "q", "g"])
30
30
  ("if(!(r instanceof Reader))")
31
31
  ("r=Reader.create(r)")
32
32
  ("if(q===undefined)q=0")
@@ -198,7 +198,7 @@ function decoder(mtype) {
198
198
  for (i = 0; i < mtype._fieldsArray.length; ++i) {
199
199
  var rfield = mtype._fieldsArray[i];
200
200
  if (rfield.required) gen
201
- ("if(!m.hasOwnProperty(%j))", rfield.name)
201
+ ("if(!Object.hasOwnProperty.call(m,%j))", rfield.name)
202
202
  ("throw util.ProtocolError(%j,{instance:m})", missing(rfield));
203
203
  }
204
204
 
package/src/encoder.js CHANGED
@@ -27,7 +27,7 @@ function genTypePartial(gen, field, fieldIndex, ref) {
27
27
  */
28
28
  function encoder(mtype) {
29
29
  /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
30
- var gen = util.codegen(["m", "w", "q"], mtype.name + "$encode")
30
+ var gen = util.codegen(["m", "w", "q"])
31
31
  ("if(!w)")
32
32
  ("w=Writer.create()")
33
33
  ("if(q===undefined)q=0")
package/src/field.js CHANGED
@@ -38,6 +38,12 @@ Field.fromJSON = function fromJSON(name, json) {
38
38
  var field = new Field(name, json.id, json.type, json.rule, json.extend, json.options, json.comment);
39
39
  if (json.edition)
40
40
  field._edition = json.edition;
41
+ if (json.protoName)
42
+ field.protoName = json.protoName;
43
+ if (json.jsonName !== undefined)
44
+ field.jsonName = json.jsonName;
45
+ else if (json.options && json.options.json_name !== undefined)
46
+ field.jsonName = json.options.json_name;
41
47
  field._defaultEdition = "proto3"; // For backwards-compatibility.
42
48
  return field;
43
49
  };
@@ -177,6 +183,18 @@ function Field(name, id, type, rule, extend, options, comment) {
177
183
  * @type {string|null}
178
184
  */
179
185
  this.comment = comment;
186
+
187
+ /**
188
+ * Field name as declared in the .proto source, if different from `name`.
189
+ * @type {string|undefined}
190
+ */
191
+ this.protoName = undefined;
192
+
193
+ /**
194
+ * JSON name, if different from the derived default.
195
+ * @type {string|undefined}
196
+ */
197
+ this.jsonName = undefined;
180
198
  }
181
199
 
182
200
  /**
@@ -246,6 +264,22 @@ Object.defineProperty(Field.prototype, "hasPresence", {
246
264
  }
247
265
  });
248
266
 
267
+ /**
268
+ * The field name as declared in the .proto source (snake_case). Populated on resolve,
269
+ * falling back to `name`. Mirrors `FieldDescriptorProto.name`.
270
+ * @name Field#protoName
271
+ * @type {string}
272
+ * @readonly
273
+ */
274
+
275
+ /**
276
+ * The JSON name of this field (lowerCamelCase per protoc's `ToJsonName`, or an
277
+ * explicit `[json_name]`). Populated on resolve. This is the key used on ProtoJSON output.
278
+ * @name Field#jsonName
279
+ * @type {string}
280
+ * @readonly
281
+ */
282
+
249
283
  /**
250
284
  * @override
251
285
  */
@@ -279,13 +313,15 @@ Field.prototype.setOption = function setOption(name, value, ifNotSet) {
279
313
  Field.prototype.toJSON = function toJSON(toJSONOptions) {
280
314
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
281
315
  return util.toObject([
282
- "edition" , this._editionToJSON(),
283
- "rule" , this.rule !== "optional" && this.rule || undefined,
284
- "type" , this.type,
285
- "id" , this.id,
286
- "extend" , this.extend,
287
- "options" , this.options,
288
- "comment" , keepComments ? this.comment : undefined
316
+ "edition" , this._editionToJSON(),
317
+ "rule" , this.rule !== "optional" && this.rule || undefined,
318
+ "type" , this.type,
319
+ "id" , this.id,
320
+ "extend" , this.extend,
321
+ "protoName" , this.protoName !== this.name ? this.protoName : undefined,
322
+ "jsonName" , this.jsonName !== util.jsonName(this.protoName || this.name) ? this.jsonName : undefined,
323
+ "options" , this.options,
324
+ "comment" , keepComments ? this.comment : undefined
289
325
  ]);
290
326
  };
291
327
 
@@ -354,6 +390,12 @@ Field.prototype.resolve = function resolve() {
354
390
  if (this.parent instanceof Type && this.parent._ctor)
355
391
  this.parent._ctor.prototype[this.name] = this.defaultValue;
356
392
 
393
+ // derive the proto/JSON names
394
+ if (this.protoName === undefined)
395
+ this.protoName = this.name;
396
+ if (this.jsonName === undefined)
397
+ this.jsonName = util.jsonName(this.protoName);
398
+
357
399
  return ReflectionObject.prototype.resolve.call(this);
358
400
  };
359
401
 
package/src/mapfield.js CHANGED
@@ -65,7 +65,14 @@ function MapField(name, id, keyType, type, options, comment) {
65
65
  * @throws {TypeError} If arguments are invalid
66
66
  */
67
67
  MapField.fromJSON = function fromJSON(name, json) {
68
- return new MapField(name, json.id, json.keyType, json.type, json.options, json.comment);
68
+ var field = new MapField(name, json.id, json.keyType, json.type, json.options, json.comment);
69
+ if (json.protoName)
70
+ field.protoName = json.protoName;
71
+ if (json.jsonName !== undefined)
72
+ field.jsonName = json.jsonName;
73
+ else if (json.options && json.options.json_name !== undefined)
74
+ field.jsonName = json.options.json_name;
75
+ return field;
69
76
  };
70
77
 
71
78
  /**
@@ -76,12 +83,14 @@ MapField.fromJSON = function fromJSON(name, json) {
76
83
  MapField.prototype.toJSON = function toJSON(toJSONOptions) {
77
84
  var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
78
85
  return util.toObject([
79
- "keyType" , this.keyType,
80
- "type" , this.type,
81
- "id" , this.id,
82
- "extend" , this.extend,
83
- "options" , this.options,
84
- "comment" , keepComments ? this.comment : undefined
86
+ "keyType" , this.keyType,
87
+ "type" , this.type,
88
+ "id" , this.id,
89
+ "extend" , this.extend,
90
+ "protoName" , this.protoName !== this.name ? this.protoName : undefined,
91
+ "jsonName" , this.jsonName !== util.jsonName(this.protoName || this.name) ? this.jsonName : undefined,
92
+ "options" , this.options,
93
+ "comment" , keepComments ? this.comment : undefined
85
94
  ]);
86
95
  };
87
96
 
package/src/parse.js CHANGED
@@ -482,10 +482,13 @@ function parse(source, root, options) {
482
482
  if (!nameRe.test(name))
483
483
  throw illegal(name, "name");
484
484
 
485
+ var protoName = name;
485
486
  name = applyCase(name);
486
487
  skip("=");
487
488
 
488
489
  var field = new Field(name, parseId(next()), type, rule === "proto3_optional" ? "optional" : rule, extend);
490
+ if (protoName !== name)
491
+ field.protoName = protoName;
489
492
 
490
493
  ifBlock(field, function parseField_block(token) {
491
494
 
@@ -627,7 +630,11 @@ function parse(source, root, options) {
627
630
  throw illegal(name, "name");
628
631
 
629
632
  skip("=");
630
- var field = new MapField(applyCase(name), parseId(next()), keyType, valueType);
633
+ var protoName = name;
634
+ name = applyCase(name);
635
+ var field = new MapField(name, parseId(next()), keyType, valueType);
636
+ if (protoName !== name)
637
+ field.protoName = protoName;
631
638
  ifBlock(field, function parseMapField_block(token) {
632
639
 
633
640
  /* istanbul ignore else */
@@ -839,11 +846,18 @@ function parse(source, root, options) {
839
846
  topLevelOptions[name] = value;
840
847
  return;
841
848
  }
849
+ // lift json_name onto Field
850
+ if (name === "json_name" && parent instanceof Field) {
851
+ parent.jsonName = value;
852
+ return;
853
+ }
842
854
  if (parent.setOption)
843
855
  parent.setOption(name, value);
844
856
  }
845
857
 
846
858
  function setParsedOption(parent, name, value, propName) {
859
+ if (name === "json_name" && parent instanceof Field)
860
+ return; // lifted onto Field#jsonName above
847
861
  if (parent.setParsedOption)
848
862
  parent.setParsedOption(name, value, propName);
849
863
  }
package/src/service.js CHANGED
@@ -9,8 +9,6 @@ var Method = require("./method"),
9
9
  util = require("./util"),
10
10
  rpc = require("./rpc");
11
11
 
12
- var reservedRe = util.patterns.reservedRe;
13
-
14
12
  /**
15
13
  * Constructs a new service instance.
16
14
  * @classdesc Reflected service.
@@ -190,11 +188,11 @@ Service.prototype.create = function create(rpcImpl, requestDelimited, responseDe
190
188
  var rpcService = new rpc.Service(rpcImpl, requestDelimited, responseDelimited);
191
189
  for (var i = 0, method; i < /* initializes */ this.methodsArray.length; ++i) {
192
190
  var methodName = util.lcFirst((method = this._methodsArray[i]).resolve().name).replace(/[^$\w_]/g, "");
193
- rpcService[methodName] = util.codegen(["r","c"], reservedRe.test(methodName) ? methodName + "_" : methodName)("return this.rpcCall(m,q,s,r,c)")({
194
- m: method,
195
- q: method.resolvedRequestType.ctor,
196
- s: method.resolvedResponseType.ctor
197
- });
191
+ rpcService[methodName] = (function(method, requestType, responseType) {
192
+ return function rpcMethod(request, callback) {
193
+ return rpc.Service.prototype.rpcCall.call(this, method, requestType, responseType, request, callback);
194
+ };
195
+ })(method, method.resolvedRequestType.ctor, method.resolvedResponseType.ctor);
198
196
  }
199
197
  return rpcService;
200
198
  };
package/src/type.js CHANGED
@@ -89,6 +89,13 @@ function Type(name, options) {
89
89
  * @private
90
90
  */
91
91
  this._ctor = null;
92
+
93
+ /**
94
+ * Cached fields by JSON name.
95
+ * @type {Object.<string,Field>|null}
96
+ * @private
97
+ */
98
+ this._fieldsByJsonName = null; // used by ext/protojson
92
99
  }
93
100
 
94
101
  Object.defineProperties(Type.prototype, {
@@ -201,7 +208,7 @@ Object.defineProperties(Type.prototype, {
201
208
  */
202
209
  Type.generateConstructor = function generateConstructor(mtype) {
203
210
  /* eslint-disable no-unexpected-multiline */
204
- var gen = util.codegen(["p"], mtype.name);
211
+ var gen = util.codegen(["p"]);
205
212
  // explicitly initialize mutable object/array fields so that these aren't just inherited from the prototype
206
213
  for (var i = 0, field; i < mtype.fieldsArray.length; ++i)
207
214
  if ((field = mtype._fieldsArray[i]).map) gen
@@ -215,7 +222,7 @@ Type.generateConstructor = function generateConstructor(mtype) {
215
222
  };
216
223
 
217
224
  function clearCache(type) {
218
- type._fieldsById = type._fieldsArray = type._oneofsArray = null;
225
+ type._fieldsById = type._fieldsArray = type._oneofsArray = type._fieldsByJsonName = null;
219
226
  delete type.encode;
220
227
  delete type.decode;
221
228
  delete type.verify;
@@ -379,7 +386,7 @@ Type.prototype.add = function add(object) {
379
386
  throw Error("duplicate id " + object.id + " in " + this);
380
387
  if (this.isReservedId(object.id))
381
388
  throw Error("id " + object.id + " is reserved in " + this);
382
- if (this.isReservedName(object.name))
389
+ if (this.isReservedName(object.name) || object.name.charAt(0) === "$")
383
390
  throw Error("name '" + object.name + "' is reserved in " + this);
384
391
  if (object.name === "__proto__")
385
392
  return this;
@@ -392,6 +399,8 @@ Type.prototype.add = function add(object) {
392
399
  return clearCache(this);
393
400
  }
394
401
  if (object instanceof OneOf) {
402
+ if (object.name.charAt(0) === "$")
403
+ throw Error("name '" + object.name + "' is reserved in " + this);
395
404
  if (object.name === "__proto__")
396
405
  return this;
397
406
  if (!this.oneofs)
@@ -13,9 +13,6 @@ util.EventEmitter = require("./eventemitter");
13
13
  // float handling accross browsers
14
14
  util.float = require("./float");
15
15
 
16
- // requires modules optionally and hides the call from bundlers
17
- util.inquire = require("./inquire");
18
-
19
16
  // converts to / from utf8 encoded strings
20
17
  util.utf8 = require("./utf8");
21
18
 
@@ -119,7 +116,7 @@ util.isset =
119
116
  */
120
117
  util.isSet = function isSet(obj, prop) {
121
118
  var value = obj[prop];
122
- if (value != null && obj.hasOwnProperty(prop)) // eslint-disable-line eqeqeq, no-prototype-builtins
119
+ if (value != null && Object.hasOwnProperty.call(obj, prop)) // eslint-disable-line eqeqeq
123
120
  return typeof value !== "object" || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0;
124
121
  return false;
125
122
  };
package/src/util.js CHANGED
@@ -93,6 +93,7 @@ var camelCaseRe = /_([a-z])/g;
93
93
  * Converts a string to camel case.
94
94
  * @param {string} str String to convert
95
95
  * @returns {string} Converted string
96
+ * @deprecated Use {@link util.jsonName} for protobuf field JSON names.
96
97
  */
97
98
  util.camelCase = function camelCase(str) {
98
99
  return str.substring(0, 1)
@@ -100,6 +101,28 @@ util.camelCase = function camelCase(str) {
100
101
  .replace(camelCaseRe, function($0, $1) { return $1.toUpperCase(); });
101
102
  };
102
103
 
104
+ /**
105
+ * Converts a proto field name to its protoc-compatible JSON name.
106
+ * @param {string} str Proto field name
107
+ * @returns {string} JSON name
108
+ */
109
+ util.jsonName = function jsonName(str) {
110
+ var result = "",
111
+ upperNext = false,
112
+ i = 0;
113
+ for (; i < str.length; ++i) {
114
+ var ch = str.charAt(i);
115
+ if (ch === "_")
116
+ upperNext = true;
117
+ else if (upperNext) {
118
+ result += ch.toUpperCase();
119
+ upperNext = false;
120
+ } else
121
+ result += ch;
122
+ }
123
+ return result;
124
+ };
125
+
103
126
  /**
104
127
  * Compares reflected fields by id.
105
128
  * @param {Field} a First field
package/src/verifier.js CHANGED
@@ -122,7 +122,7 @@ function genVerifyKey(gen, field, ref) {
122
122
  function verifier(mtype) {
123
123
  /* eslint-disable no-unexpected-multiline */
124
124
 
125
- var gen = util.codegen(["m", "q"], mtype.name + "$verify")
125
+ var gen = util.codegen(["m", "q"])
126
126
  ("if(typeof m!==\"object\"||m===null)")
127
127
  ("return%j", "object expected")
128
128
  ("if(q===undefined)q=0")
@@ -138,7 +138,7 @@ function verifier(mtype) {
138
138
  ref = "m" + util.safeProp(field.name);
139
139
 
140
140
  if (field.optional) gen
141
- ("if(%s!=null&&m.hasOwnProperty(%j)){", ref, field.name); // !== undefined && !== null
141
+ ("if(%s!=null&&Object.hasOwnProperty.call(m,%j)){", ref, field.name); // !== undefined && !== null
142
142
 
143
143
  // map fields
144
144
  if (field.map) { gen