Skip to content

Commit

Permalink
New: Implemented stubs for long.js / node buffers to be used where ei…
Browse files Browse the repository at this point in the history
…ther one isn't wanted, see #718
  • Loading branch information
dcodeIO committed Mar 23, 2017
1 parent a06691f commit c04d4a5
Show file tree
Hide file tree
Showing 22 changed files with 423 additions and 403 deletions.
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Where bundle size is a factor, there is a suitable distribution for each of thes
| 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.
| minimal | 6.0kb+ | [dist/minimal][dist-minimal] | `require("protobufjs/minimal")` | Just enough to run static code. No reflection.

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

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

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.

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

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

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

**What is a valid message?**
### Valid message

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.

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

| Type | Expected JS type (create) | Naive conversion (fromObject)
|--------|-----------------|-------------------
| int32<br />uint32<br />sint32<br />fixed32<br />sfixed32 | `Number` (32 bit integer) | `value | 0`<br /> `value >>> 0`
| 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
| Field type | Expected JS type (create, encode) | Naive conversion (fromObject)
|------------|-----------------------------------|------------------------------
| s-/u-/int32<br />s-/fixed32 | `Number` (32 bit integer) | `value | 0` if signed<br /> `value >>> 0` if unsigned
| 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
| float<br />double | `Number` | `Number(value)`
| bool | `Boolean` | `Boolean(value)`
| string | `String` | `String(value)`
| 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
| 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
| enum | `Number` (32 bit integer) | Looks up the numeric id if a string
| message | Valid message | `Message.fromObject(value)`

* Explicit `undefined` and `null` are considered as not set when optional.
* Repeated fields are `Array.<T>`.
* 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.
* 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.
* `String` refers to both objects and values while `Number` refers to values only.
* 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.

Examples
--------
Expand Down
6 changes: 4 additions & 2 deletions cli/targets/static.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,9 @@ function buildType(ref, type) {
jsType = "Object.<string," + jsType + ">";
else if (field.repeated)
jsType = "Array.<" + jsType + ">";
typeDef.push("@property {" + jsType + "} " + (field.optional ? "[" + field.name + "]" : field.name) + " " + (field.comment || type.name + " " + field.name + "."));
var name = util.safeProp(field.name);
name = name.substring(1, name.charAt(0) === "[" ? name.length - 1 : name.length);
typeDef.push("@property {" + jsType + "} " + (field.optional ? "[" + name + "]" : field.name) + " " + (field.comment || type.name + " " + field.name + "."));
});
push("");
pushComment(typeDef);
Expand Down Expand Up @@ -391,7 +393,7 @@ function buildType(ref, type) {
push("");
pushComment([
"Encodes the specified " + type.name + " message, length delimited. Does not implicitly {@link " + fullName + ".verify|verify} messages.",
"@param {" + fullName + "|Object.<string,*>} message " + type.name + " message or plain object to encode",
"@param {" + fullName + "$Properties} message " + type.name + " message or plain object to encode",
"@param {$protobuf.Writer} [writer] Writer to encode to",
"@returns {$protobuf.Writer} Writer"
]);
Expand Down
4 changes: 3 additions & 1 deletion debug.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
// experimental - debug library entry point.

"use strict";
module.exports = require("./src/index-debug");
module.exports = require("./src/index-debug");
24 changes: 4 additions & 20 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1842,15 +1842,15 @@ export class Type extends NamespaceBase {
* @property {boolean} [objects=false] Sets empty objects for missing map fields even if `defaults=false`
* @property {boolean} [oneofs=false] Includes virtual oneof properties set to the present field's name, if any
*/
interface ConversionOptions {
type ConversionOptions = {
longs?: any;
enums?: any;
bytes?: any;
defaults?: boolean;
arrays?: boolean;
objects?: boolean;
oneofs?: boolean;
}
};

/**
* Common type constants.
Expand Down Expand Up @@ -2016,22 +2016,6 @@ export namespace types {
};
}

/**
* Any compatible Long instance.
*
* This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.
* @typedef Long
* @type {Object}
* @property {number} low Low bits
* @property {number} high High bits
* @property {boolean} unsigned Whether unsigned or not
*/
interface Long {
low: number;
high: number;
unsigned: boolean;
}

/**
* Various utility functions.
* @namespace
Expand Down Expand Up @@ -2870,10 +2854,10 @@ type FetchCallback = (error: Error, contents?: string) => void;
* @property {boolean} [binary=false] Whether expecting a binary response
* @property {boolean} [xhr=false] If `true`, forces the use of XMLHttpRequest
*/
interface FetchOptions {
type FetchOptions = {
binary?: boolean;
xhr?: boolean;
}
};

/**
* An allocator as used by {@link util.pool}.
Expand Down
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
// full library entry point.

"use strict";
module.exports = require("./src/index");
16 changes: 12 additions & 4 deletions lib/tsd-jsdoc/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function isClassLike(element) {

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

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

// writes (a typedef as) an interface
function writeInterface(element) {
writeln("interface ", element.name, " {");
write("interface ", element.name);
writeInterfaceBody(element);
writeln();
}

function writeInterfaceBody(element) {
writeln("{");
++indent;
element.properties.forEach(function(property) {
write(property.name);
Expand All @@ -305,7 +311,7 @@ function writeInterface(element) {
writeln(": ", getTypeOf(property), ";");
});
--indent;
writeln("}");
write("}");
}

//
Expand Down Expand Up @@ -524,7 +530,9 @@ function handleTypeDef(element, parent) {
write("type ", element.name, " = ");
if (element.type && element.type.names.length === 1 && element.type.names[0] === "function")
writeFunctionSignature(element, false, true);
else
else if (getTypeOf(element) === "Object" && element.properties && element.properties.length) {
writeInterfaceBody(element);
} else
write(getTypeOf(element));
writeln(";");
}
Expand Down
2 changes: 2 additions & 0 deletions light.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
// light library entry point.

"use strict";
module.exports = require("./src/index-light");
4 changes: 3 additions & 1 deletion minimal.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
// minimal library entry point.

"use strict";
module.exports = require("./src/index-minimal");
module.exports = require("./src/index-minimal");
5 changes: 3 additions & 2 deletions runtime.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// deprecated - compatibility layer for v6.5 and earlier
// deprecated - compatibility layer for v6.5 and earlier (now named "minimal")

"use strict";
module.exports = require("./src/index-minimal");
module.exports = require("./src/index-minimal");
11 changes: 0 additions & 11 deletions src/util/longbits.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,6 @@ module.exports = LongBits;

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

/**
* Any compatible Long instance.
*
* This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.
* @typedef Long
* @type {Object}
* @property {number} low Low bits
* @property {number} high High bits
* @property {boolean} unsigned Whether unsigned or not
*/

/**
* Constructs new long bits.
* @classdesc Helper class for working with the low and high bits of a 64 bit value.
Expand Down
17 changes: 17 additions & 0 deletions src/util/minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ util.isObject = function isObject(value) {
return value && typeof value === "object";
};

/*
* Any compatible Buffer instance.
* This is a minimal stand-alone definition of a Buffer instance. The actual type is that exported by node's typings.
* @typedef Buffer
* @type {Uint8Array}
*/

/**
* Node's Buffer class if available.
* @type {?function(new: Buffer)}
Expand Down Expand Up @@ -128,6 +135,16 @@ util.newBuffer = function newBuffer(sizeOrArray) {
*/
util.Array = typeof Uint8Array !== "undefined" ? Uint8Array /* istanbul ignore next */ : Array;

/*
* Any compatible Long instance.
* This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.
* @typedef Long
* @type {Object}
* @property {number} low Low bits
* @property {number} high High bits
* @property {boolean} unsigned Whether unsigned or not
*/

/**
* Long.js's Long class if available.
* @type {?function(new: Long)}
Expand Down
9 changes: 9 additions & 0 deletions stub-long.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// minimal stub for Long instances for reference when not using long.js.

type Long = LongStub;

interface LongStub {
lo: number,
hi: number,
unsigned: boolean
}
6 changes: 6 additions & 0 deletions stub-node.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// minimal stub for node types for reference when not using node.

type Buffer = BufferStub;

interface BufferStub extends Uint8Array {
}
11 changes: 9 additions & 2 deletions tests/comp_typescript.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
// uncomment for browser only / non long.js versions
/*
/// <reference path="../stub-long.d.ts" />
/// <reference path="../stub-node.d.ts" />
*/

import * as protobuf from "..";

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

let hello = new Hello();

let buf = Hello.encode(hello.foo()).finish();
let writer = Hello.encode(hello.foo()) as protobuf.BufferWriter;
let buf = writer.finish();

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

export const utf8 = protobuf.util.utf8;
10 changes: 5 additions & 5 deletions tests/data/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ $root.Test1 = (function() {

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

/**
* Encodes the specified Test2 message, length delimited. Does not implicitly {@link Test2.verify|verify} messages.
* @param {Test2|Object.<string,*>} message Test2 message or plain object to encode
* @param {Test2$Properties} message Test2 message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Expand Down Expand Up @@ -373,9 +373,9 @@ $root.Test2 = (function() {
*/
$root.Test3 = (function() {
var valuesById = {}, values = Object.create(valuesById);
values["ONE"] = 1;
values["TWO"] = 2;
values["THREE"] = 3;
values[valuesById[1] = "ONE"] = 1;
values[valuesById[2] = "TWO"] = 2;
values[valuesById[3] = "THREE"] = 3;
return values;
})();

Expand Down
6 changes: 3 additions & 3 deletions tests/data/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ $root.Message = (function() {

/**
* Encodes the specified Message message, length delimited. Does not implicitly {@link Message.verify|verify} messages.
* @param {Message|Object.<string,*>} message Message message or plain object to encode
* @param {Message$Properties} message Message message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Expand Down Expand Up @@ -479,8 +479,8 @@ $root.Message = (function() {
*/
Message.SomeEnum = (function() {
var valuesById = {}, values = Object.create(valuesById);
values["ONE"] = 1;
values["TWO"] = 2;
values[valuesById[1] = "ONE"] = 1;
values[valuesById[2] = "TWO"] = 2;
return values;
})();

Expand Down
16 changes: 8 additions & 8 deletions tests/data/mapbox/vector_tile.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ $root.vector_tile = (function() {

/**
* Encodes the specified Tile message, length delimited. Does not implicitly {@link vector_tile.Tile.verify|verify} messages.
* @param {vector_tile.Tile|Object.<string,*>} message Tile message or plain object to encode
* @param {vector_tile.Tile$Properties} message Tile message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Expand Down Expand Up @@ -218,10 +218,10 @@ $root.vector_tile = (function() {
*/
Tile.GeomType = (function() {
var valuesById = {}, values = Object.create(valuesById);
values["UNKNOWN"] = 0;
values["POINT"] = 1;
values["LINESTRING"] = 2;
values["POLYGON"] = 3;
values[valuesById[0] = "UNKNOWN"] = 0;
values[valuesById[1] = "POINT"] = 1;
values[valuesById[2] = "LINESTRING"] = 2;
values[valuesById[3] = "POLYGON"] = 3;
return values;
})();

Expand Down Expand Up @@ -298,7 +298,7 @@ $root.vector_tile = (function() {

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

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

/**
* Encodes the specified Layer message, length delimited. Does not implicitly {@link vector_tile.Tile.Layer.verify|verify} messages.
* @param {vector_tile.Tile.Layer|Object.<string,*>} message Layer message or plain object to encode
* @param {vector_tile.Tile.Layer$Properties} message Layer message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Expand Down
Loading

0 comments on commit c04d4a5

Please sign in to comment.