Skip to content

Commit c04d4a5

Browse files
committed
New: Implemented stubs for long.js / node buffers to be used where either one isn't wanted, see #718
1 parent a06691f commit c04d4a5

22 files changed

+423
-403
lines changed

README.md

+12-11
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Where bundle size is a factor, there is a suitable distribution for each of thes
7777
| light | 15.5kb | [dist/light][dist-light] | `require("protobufjs/light")` | All features except tokenizer, parser and bundled common types. Works with JSON definitions, pure reflection and static code.
7878
| minimal | 6.0kb+ | [dist/minimal][dist-minimal] | `require("protobufjs/minimal")` | Just enough to run static code. No reflection.
7979

80-
In case of doubt you can just use the full library.
80+
In case of doubt it is safe to just use the full library.
8181

8282
[dist-full]: https://github.com/dcodeIO/protobuf.js/tree/master/dist
8383
[dist-light]: https://github.com/dcodeIO/protobuf.js/tree/master/dist/light
@@ -88,7 +88,7 @@ Usage
8888

8989
Each message type provides a set of methods with each method doing just one thing. This allows to avoid unnecessary operations where [performance](#performance) is a concern but also forces a user to perform verification explicitly where necessary - for example when dealing with user input.
9090

91-
Note that **Message** refers to any message type below.
91+
Note that **Message** below refers to any message type. See the next section for the definition of a [valid message](#valid-message).
9292

9393
* **Message.verify**(message: `Object`): `null|string`<br />
9494
explicitly performs verification prior to encoding a plain object. Instead of throwing, it returns the error message as a string, if any.
@@ -160,29 +160,30 @@ Note that **Message** refers to any message type below.
160160

161161
See also: [ConversionOptions](http://dcode.io/protobuf.js/global.html#ConversionOptions)
162162

163-
**What is a valid message?**
163+
### Valid message
164164

165165
A valid message is an object not missing any required fields and exclusively using JS types for its fields that are understood by the wire format writer.
166166

167-
* Calling `Message.verify` with a valid message returns `null` and otherwise the error as a string.
168-
* Calling `Message.create` or `Message.encode` with any object assumes valid types.
167+
* Calling `Message.verify` with any object returns `null` if the object can be encoded as-is and otherwise the error as a string.
168+
* Calling `Message.create` or `Message.encode` must be called with a valid message.
169169
* Calling `Message.fromObject` with any object naively converts all values to the optimal JS type.
170170

171-
| Type | Expected JS type (create) | Naive conversion (fromObject)
172-
|--------|-----------------|-------------------
173-
| int32<br />uint32<br />sint32<br />fixed32<br />sfixed32 | `Number` (32 bit integer) | `value | 0`<br /> `value >>> 0`
174-
| int64<br />uint64<br />sint64<br />fixed64<br />sfixed64 | `Long`-like (optimal)<br />`Number` (53 bit integer) | `Long.fromValue(value)`<br />`parseInt(value, 10)` without long.js
171+
| Field type | Expected JS type (create, encode) | Naive conversion (fromObject)
172+
|------------|-----------------------------------|------------------------------
173+
| s-/u-/int32<br />s-/fixed32 | `Number` (32 bit integer) | `value | 0` if signed<br /> `value >>> 0` if unsigned
174+
| s-/u-/int64<br />s-/fixed64 | `Long`-like (optimal)<br />`Number` (53 bit integer) | `Long.fromValue(value)` with long.js<br />`parseInt(value, 10)` otherwise
175175
| float<br />double | `Number` | `Number(value)`
176176
| bool | `Boolean` | `Boolean(value)`
177177
| string | `String` | `String(value)`
178-
| bytes | `Uint8Array` (optimal)<br />`Buffer` (optimal)<br />`Array.<Number>` (8 bit integers)<br />`String` (base64) | `base64.decode(value)` if a String<br />`Object` with non-zero `.length` is kept
178+
| bytes | `Uint8Array` (optimal)<br />`Buffer` (optimal under node)<br />`Array.<Number>` (8 bit integers)<br />`String` (base64) | `base64.decode(value)` if a String<br />`Object` with non-zero `.length` is kept
179179
| enum | `Number` (32 bit integer) | Looks up the numeric id if a string
180180
| message | Valid message | `Message.fromObject(value)`
181181

182182
* Explicit `undefined` and `null` are considered as not set when optional.
183183
* Repeated fields are `Array.<T>`.
184-
* Map fields are `Object.<string,T>` with the key being the string representation of the respective value or an 8 characters long binary hash string for Long-likes.
184+
* Map fields are `Object.<string,T>` with the key being the string representation of the respective value or an 8 characters long binary hash string for `Long`-likes.
185185
* `String` refers to both objects and values while `Number` refers to values only.
186+
* Types marked as *optimal* provide the best performance because no conversion step (i.e. number to low and high bits or base64 string to buffer) is required.
186187

187188
Examples
188189
--------

cli/targets/static.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,9 @@ function buildType(ref, type) {
296296
jsType = "Object.<string," + jsType + ">";
297297
else if (field.repeated)
298298
jsType = "Array.<" + jsType + ">";
299-
typeDef.push("@property {" + jsType + "} " + (field.optional ? "[" + field.name + "]" : field.name) + " " + (field.comment || type.name + " " + field.name + "."));
299+
var name = util.safeProp(field.name);
300+
name = name.substring(1, name.charAt(0) === "[" ? name.length - 1 : name.length);
301+
typeDef.push("@property {" + jsType + "} " + (field.optional ? "[" + name + "]" : field.name) + " " + (field.comment || type.name + " " + field.name + "."));
300302
});
301303
push("");
302304
pushComment(typeDef);
@@ -391,7 +393,7 @@ function buildType(ref, type) {
391393
push("");
392394
pushComment([
393395
"Encodes the specified " + type.name + " message, length delimited. Does not implicitly {@link " + fullName + ".verify|verify} messages.",
394-
"@param {" + fullName + "|Object.<string,*>} message " + type.name + " message or plain object to encode",
396+
"@param {" + fullName + "$Properties} message " + type.name + " message or plain object to encode",
395397
"@param {$protobuf.Writer} [writer] Writer to encode to",
396398
"@returns {$protobuf.Writer} Writer"
397399
]);

debug.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
// experimental - debug library entry point.
2+
13
"use strict";
2-
module.exports = require("./src/index-debug");
4+
module.exports = require("./src/index-debug");

index.d.ts

+4-20
Original file line numberDiff line numberDiff line change
@@ -1842,15 +1842,15 @@ export class Type extends NamespaceBase {
18421842
* @property {boolean} [objects=false] Sets empty objects for missing map fields even if `defaults=false`
18431843
* @property {boolean} [oneofs=false] Includes virtual oneof properties set to the present field's name, if any
18441844
*/
1845-
interface ConversionOptions {
1845+
type ConversionOptions = {
18461846
longs?: any;
18471847
enums?: any;
18481848
bytes?: any;
18491849
defaults?: boolean;
18501850
arrays?: boolean;
18511851
objects?: boolean;
18521852
oneofs?: boolean;
1853-
}
1853+
};
18541854

18551855
/**
18561856
* Common type constants.
@@ -2016,22 +2016,6 @@ export namespace types {
20162016
};
20172017
}
20182018

2019-
/**
2020-
* Any compatible Long instance.
2021-
*
2022-
* This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.
2023-
* @typedef Long
2024-
* @type {Object}
2025-
* @property {number} low Low bits
2026-
* @property {number} high High bits
2027-
* @property {boolean} unsigned Whether unsigned or not
2028-
*/
2029-
interface Long {
2030-
low: number;
2031-
high: number;
2032-
unsigned: boolean;
2033-
}
2034-
20352019
/**
20362020
* Various utility functions.
20372021
* @namespace
@@ -2870,10 +2854,10 @@ type FetchCallback = (error: Error, contents?: string) => void;
28702854
* @property {boolean} [binary=false] Whether expecting a binary response
28712855
* @property {boolean} [xhr=false] If `true`, forces the use of XMLHttpRequest
28722856
*/
2873-
interface FetchOptions {
2857+
type FetchOptions = {
28742858
binary?: boolean;
28752859
xhr?: boolean;
2876-
}
2860+
};
28772861

28782862
/**
28792863
* An allocator as used by {@link util.pool}.

index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
// full library entry point.
2+
13
"use strict";
24
module.exports = require("./src/index");

lib/tsd-jsdoc/publish.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ function isClassLike(element) {
177177

178178
// tests if an element is considered to be an interface
179179
function isInterface(element) {
180-
return element && (element.kind === "interface" || getTypeOf(element) === "Object" && element.properties && element.properties.length);
180+
return element && element.kind === "interface";
181181
}
182182

183183
// tests if an element is considered to be a namespace
@@ -296,7 +296,13 @@ function writeFunctionSignature(element, isConstructor, isTypeDef) {
296296

297297
// writes (a typedef as) an interface
298298
function writeInterface(element) {
299-
writeln("interface ", element.name, " {");
299+
write("interface ", element.name);
300+
writeInterfaceBody(element);
301+
writeln();
302+
}
303+
304+
function writeInterfaceBody(element) {
305+
writeln("{");
300306
++indent;
301307
element.properties.forEach(function(property) {
302308
write(property.name);
@@ -305,7 +311,7 @@ function writeInterface(element) {
305311
writeln(": ", getTypeOf(property), ";");
306312
});
307313
--indent;
308-
writeln("}");
314+
write("}");
309315
}
310316

311317
//
@@ -524,7 +530,9 @@ function handleTypeDef(element, parent) {
524530
write("type ", element.name, " = ");
525531
if (element.type && element.type.names.length === 1 && element.type.names[0] === "function")
526532
writeFunctionSignature(element, false, true);
527-
else
533+
else if (getTypeOf(element) === "Object" && element.properties && element.properties.length) {
534+
writeInterfaceBody(element);
535+
} else
528536
write(getTypeOf(element));
529537
writeln(";");
530538
}

light.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
// light library entry point.
2+
13
"use strict";
24
module.exports = require("./src/index-light");

minimal.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
// minimal library entry point.
2+
13
"use strict";
2-
module.exports = require("./src/index-minimal");
4+
module.exports = require("./src/index-minimal");

runtime.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
// deprecated - compatibility layer for v6.5 and earlier
1+
// deprecated - compatibility layer for v6.5 and earlier (now named "minimal")
2+
23
"use strict";
3-
module.exports = require("./src/index-minimal");
4+
module.exports = require("./src/index-minimal");

src/util/longbits.js

-11
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,6 @@ module.exports = LongBits;
33

44
var util = require("../util/minimal");
55

6-
/**
7-
* Any compatible Long instance.
8-
*
9-
* This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.
10-
* @typedef Long
11-
* @type {Object}
12-
* @property {number} low Low bits
13-
* @property {number} high High bits
14-
* @property {boolean} unsigned Whether unsigned or not
15-
*/
16-
176
/**
187
* Constructs new long bits.
198
* @classdesc Helper class for working with the low and high bits of a 64 bit value.

src/util/minimal.js

+17
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ util.isObject = function isObject(value) {
7070
return value && typeof value === "object";
7171
};
7272

73+
/*
74+
* Any compatible Buffer instance.
75+
* This is a minimal stand-alone definition of a Buffer instance. The actual type is that exported by node's typings.
76+
* @typedef Buffer
77+
* @type {Uint8Array}
78+
*/
79+
7380
/**
7481
* Node's Buffer class if available.
7582
* @type {?function(new: Buffer)}
@@ -128,6 +135,16 @@ util.newBuffer = function newBuffer(sizeOrArray) {
128135
*/
129136
util.Array = typeof Uint8Array !== "undefined" ? Uint8Array /* istanbul ignore next */ : Array;
130137

138+
/*
139+
* Any compatible Long instance.
140+
* This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.
141+
* @typedef Long
142+
* @type {Object}
143+
* @property {number} low Low bits
144+
* @property {number} high High bits
145+
* @property {boolean} unsigned Whether unsigned or not
146+
*/
147+
131148
/**
132149
* Long.js's Long class if available.
133150
* @type {?function(new: Long)}

stub-long.d.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// minimal stub for Long instances for reference when not using long.js.
2+
3+
type Long = LongStub;
4+
5+
interface LongStub {
6+
lo: number,
7+
hi: number,
8+
unsigned: boolean
9+
}

stub-node.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// minimal stub for node types for reference when not using node.
2+
3+
type Buffer = BufferStub;
4+
5+
interface BufferStub extends Uint8Array {
6+
}

tests/comp_typescript.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
// uncomment for browser only / non long.js versions
2+
/*
3+
/// <reference path="../stub-long.d.ts" />
4+
/// <reference path="../stub-node.d.ts" />
5+
*/
6+
17
import * as protobuf from "..";
28

39
export const proto = {
@@ -30,9 +36,10 @@ protobuf.Class.create(root.lookupType("Hello"), Hello);
3036

3137
let hello = new Hello();
3238

33-
let buf = Hello.encode(hello.foo()).finish();
39+
let writer = Hello.encode(hello.foo()) as protobuf.BufferWriter;
40+
let buf = writer.finish();
3441

3542
let hello2 = Hello.decode(buf) as Hello;
36-
process.stdout.write(JSON.stringify(hello2.foo().toObject(), null, 2));
43+
// console.log(JSON.stringify(hello2.foo().toObject(), null, 2));
3744

3845
export const utf8 = protobuf.util.utf8;

tests/data/comments.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ $root.Test1 = (function() {
7070

7171
/**
7272
* Encodes the specified Test1 message, length delimited. Does not implicitly {@link Test1.verify|verify} messages.
73-
* @param {Test1|Object.<string,*>} message Test1 message or plain object to encode
73+
* @param {Test1$Properties} message Test1 message or plain object to encode
7474
* @param {$protobuf.Writer} [writer] Writer to encode to
7575
* @returns {$protobuf.Writer} Writer
7676
*/
@@ -258,7 +258,7 @@ $root.Test2 = (function() {
258258

259259
/**
260260
* Encodes the specified Test2 message, length delimited. Does not implicitly {@link Test2.verify|verify} messages.
261-
* @param {Test2|Object.<string,*>} message Test2 message or plain object to encode
261+
* @param {Test2$Properties} message Test2 message or plain object to encode
262262
* @param {$protobuf.Writer} [writer] Writer to encode to
263263
* @returns {$protobuf.Writer} Writer
264264
*/
@@ -373,9 +373,9 @@ $root.Test2 = (function() {
373373
*/
374374
$root.Test3 = (function() {
375375
var valuesById = {}, values = Object.create(valuesById);
376-
values["ONE"] = 1;
377-
values["TWO"] = 2;
378-
values["THREE"] = 3;
376+
values[valuesById[1] = "ONE"] = 1;
377+
values[valuesById[2] = "TWO"] = 2;
378+
values[valuesById[3] = "THREE"] = 3;
379379
return values;
380380
})();
381381

tests/data/convert.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ $root.Message = (function() {
106106

107107
/**
108108
* Encodes the specified Message message, length delimited. Does not implicitly {@link Message.verify|verify} messages.
109-
* @param {Message|Object.<string,*>} message Message message or plain object to encode
109+
* @param {Message$Properties} message Message message or plain object to encode
110110
* @param {$protobuf.Writer} [writer] Writer to encode to
111111
* @returns {$protobuf.Writer} Writer
112112
*/
@@ -479,8 +479,8 @@ $root.Message = (function() {
479479
*/
480480
Message.SomeEnum = (function() {
481481
var valuesById = {}, values = Object.create(valuesById);
482-
values["ONE"] = 1;
483-
values["TWO"] = 2;
482+
values[valuesById[1] = "ONE"] = 1;
483+
values[valuesById[2] = "TWO"] = 2;
484484
return values;
485485
})();
486486

tests/data/mapbox/vector_tile.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ $root.vector_tile = (function() {
6969

7070
/**
7171
* Encodes the specified Tile message, length delimited. Does not implicitly {@link vector_tile.Tile.verify|verify} messages.
72-
* @param {vector_tile.Tile|Object.<string,*>} message Tile message or plain object to encode
72+
* @param {vector_tile.Tile$Properties} message Tile message or plain object to encode
7373
* @param {$protobuf.Writer} [writer] Writer to encode to
7474
* @returns {$protobuf.Writer} Writer
7575
*/
@@ -218,10 +218,10 @@ $root.vector_tile = (function() {
218218
*/
219219
Tile.GeomType = (function() {
220220
var valuesById = {}, values = Object.create(valuesById);
221-
values["UNKNOWN"] = 0;
222-
values["POINT"] = 1;
223-
values["LINESTRING"] = 2;
224-
values["POLYGON"] = 3;
221+
values[valuesById[0] = "UNKNOWN"] = 0;
222+
values[valuesById[1] = "POINT"] = 1;
223+
values[valuesById[2] = "LINESTRING"] = 2;
224+
values[valuesById[3] = "POLYGON"] = 3;
225225
return values;
226226
})();
227227

@@ -298,7 +298,7 @@ $root.vector_tile = (function() {
298298

299299
/**
300300
* Encodes the specified Value message, length delimited. Does not implicitly {@link vector_tile.Tile.Value.verify|verify} messages.
301-
* @param {vector_tile.Tile.Value|Object.<string,*>} message Value message or plain object to encode
301+
* @param {vector_tile.Tile.Value$Properties} message Value message or plain object to encode
302302
* @param {$protobuf.Writer} [writer] Writer to encode to
303303
* @returns {$protobuf.Writer} Writer
304304
*/
@@ -599,7 +599,7 @@ $root.vector_tile = (function() {
599599

600600
/**
601601
* Encodes the specified Feature message, length delimited. Does not implicitly {@link vector_tile.Tile.Feature.verify|verify} messages.
602-
* @param {vector_tile.Tile.Feature|Object.<string,*>} message Feature message or plain object to encode
602+
* @param {vector_tile.Tile.Feature$Properties} message Feature message or plain object to encode
603603
* @param {$protobuf.Writer} [writer] Writer to encode to
604604
* @returns {$protobuf.Writer} Writer
605605
*/
@@ -904,7 +904,7 @@ $root.vector_tile = (function() {
904904

905905
/**
906906
* Encodes the specified Layer message, length delimited. Does not implicitly {@link vector_tile.Tile.Layer.verify|verify} messages.
907-
* @param {vector_tile.Tile.Layer|Object.<string,*>} message Layer message or plain object to encode
907+
* @param {vector_tile.Tile.Layer$Properties} message Layer message or plain object to encode
908908
* @param {$protobuf.Writer} [writer] Writer to encode to
909909
* @returns {$protobuf.Writer} Writer
910910
*/

0 commit comments

Comments
 (0)