From ef71e77726b6bf5978b948d598c18bf8b237ade4 Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Sat, 25 Mar 2017 22:27:38 +0100 Subject: [PATCH] Docs: Added type definitions for all possible JSON descriptors --- README.md | 40 ++++--- config/eslint.json | 2 +- index.d.ts | 284 ++++++++++++++++++++++++++++++++++++++------ src/enum.js | 15 ++- src/field.js | 28 ++++- src/mapfield.js | 28 ++++- src/method.js | 18 ++- src/namespace.js | 21 +++- src/object.js | 4 +- src/oneof.js | 17 ++- src/root.js | 4 +- src/service.js | 40 ++++--- src/type.js | 106 ++++++++++------- src/util/minimal.js | 10 +- 14 files changed, 474 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 68ce7a0f9..c3f8e97bf 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ protobuf.load("awesome.proto", function(err, root) { var message = AwesomeMessage.decode(buffer); // ... do something with message - // If your application uses length-delimited buffers, there is also encodeDelimited and decodeDelimited. + // If the application uses length-delimited buffers, there is also encodeDelimited and decodeDelimited. // Maybe convert the message back to a plain object var object = AwesomeMessage.toObject(message, { @@ -252,7 +252,7 @@ protobuf.load("awesome.proto") ### Using JSON descriptors -The library utilizes a JSON format that is equivalent to a .proto definition. For example, the following is identical to the .proto definition seen above: +The library utilizes JSON descriptors that are equivalent to a .proto definition. For example, the following is identical to the .proto definition seen above: ```json // awesome.json @@ -270,24 +270,26 @@ The library utilizes a JSON format that is equivalent to a .proto definition. Fo } ``` -The JSON format closely resembles the internal reflection structure: +JSON descriptors closely resemble the internal reflection structure: | Type (T) | Extends | Type-specific properties |--------------------|--------------------|------------------------- | *ReflectionObject* | | options | *Namespace* | *ReflectionObject* | nested +| Root | *Namespace* | **nested** | Type | *Namespace* | **fields** | Enum | *ReflectionObject* | **values** | Field | *ReflectionObject* | rule, **type**, **id** | MapField | Field | **keyType** +| OneOf | *ReflectionObject* | **oneof** (array of field names) | Service | *Namespace* | **methods** -| Method | *ReflectionObject* | *type*, **requestType**, **responseType**, requestStream, responseStream +| Method | *ReflectionObject* | type, **requestType**, **responseType**, requestStream, responseStream -* **Bold** properties are required. *Italic* types are abstract. +* **Bold properties** are required. *Italic types* are abstract. * `T.fromJSON(name, json)` creates the respective reflection object from a JSON descriptor -* `T#toJSON()` creates a JSON descriptor from the respective reflection object (`name` is used as the key within the parent) +* `T#toJSON()` creates a JSON descriptor from the respective reflection object (its name is used as the key within the parent) -Exclusively using JSON instead of .proto files enables the use of just the light library (the parser isn't required in this case). +Exclusively using JSON descriptors instead of .proto files enables the use of just the light library (the parser isn't required in this case). A JSON descriptor can either be loaded the usual way: @@ -299,7 +301,7 @@ protobuf.load("awesome.json", function(err, root) { }); ``` -Or you can load it inline: +Or it can be loaded inline: ```js var jsonDescriptor = require("./awesome.json"); // exemplary for node @@ -311,7 +313,7 @@ var root = protobuf.Root.fromJSON(jsonDescriptor); ### Using reflection only -Both the full and the light library include full reflection support. You could, for example, define the .proto definitions seen in the examples above using just reflection: +Both the full and the light library include full reflection support. One could, for example, define the .proto definitions seen in the examples above using just reflection: ```js ... @@ -331,21 +333,21 @@ Detailed information on the reflection structure is available within the [docume ### Using custom classes -You can also extend runtime message classes with your own custom functionality and even register your own constructor with a reflected message type: +Runtime message classes can also be extended with custom functionality and it is also possible to register a custom constructor with a reflected message type: ```js ... -// Define your own constructor +// Define a custom constructor function AwesomeMessage(properties) { // custom initialization code ... } -// Register your constructor with its reflected type (*) +// Register the custom constructor with its reflected type (*) root.lookupType("awesomepackage.AwesomeMessage").ctor = AwesomeMessage; -// Define your custom functionality +// Define custom functionality AwesomeMessage.customStaticMethod = function() { ... }; AwesomeMessage.prototype.customInstanceMethod = function() { ... }; @@ -362,7 +364,7 @@ AwesomeMessage.prototype.customInstanceMethod = function() { ... }; Afterwards, decoded messages of this type are `instanceof AwesomeMessage`. -Alternatively, you can also just reuse and extend the internal constructor if custom initialization code is not required: +Alternatively, it is also possible to reuse and extend the internal constructor if custom initialization code is not required: ```js ... @@ -370,7 +372,7 @@ Alternatively, you can also just reuse and extend the internal constructor if cu // Reuse the internal constructor var AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage").ctor; -// Define your custom functionality +// Define custom functionality AwesomeMessage.customStaticMethod = function() { ... }; AwesomeMessage.prototype.customInstanceMethod = function() { ... }; @@ -494,7 +496,7 @@ Documentation Command line ------------ -Command line usage has moved to the (soon to be decoupled) [CLI package]((./cli/README.md)) +Command line usage has moved to the (soon to be decoupled) [CLI package](./cli/README.md) Performance ----------- @@ -576,7 +578,7 @@ Compatibility * If typed arrays are not supported by the environment, plain arrays will be used instead. * Support for pre-ES5 environments (except IE8) can be achieved by [using a polyfill](https://github.com/dcodeIO/protobuf.js/blob/master/scripts/polyfill.js). * Support for [Content Security Policy](https://w3c.github.io/webappsec-csp/)-restricted environments (like Chrome extensions without [unsafe-eval](https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing-eval)) can be achieved by generating and using static code instead. -* If you need a proper way to work with 64 bit values (uint64, int64 etc.), you can install [long.js](https://github.com/dcodeIO/long.js) alongside this library. All 64 bit numbers will then be returned as a `Long` instance instead of a possibly unsafe JavaScript number ([see](https://github.com/dcodeIO/long.js)). +* If a proper way to work with 64 bit values (uint64, int64 etc.) is required, just install [long.js](https://github.com/dcodeIO/long.js) alongside this library. All 64 bit numbers will then be returned as a `Long` instance instead of a possibly unsafe JavaScript number ([see](https://github.com/dcodeIO/long.js)). Building -------- @@ -609,9 +611,9 @@ $> npm run types ### Browserify integration -By default, protobuf.js integrates into your browserify build-process without requiring any optional modules. Hence: +By default, protobuf.js integrates into any browserify build-process without requiring any optional modules. Hence: -* If you need int64 support, explicitly require the `long` module somewhere in your project as it will be excluded otherwise. This assumes that a global `require` function is present that protobuf.js can call to obtain the long module. +* If int64 support is required, explicitly require the `long` module somewhere in your project as it will be excluded otherwise. This assumes that a global `require` function is present that protobuf.js can call to obtain the long module. If there is no global `require` function present after bundling, it's also possible to assign the long module programmatically: diff --git a/config/eslint.json b/config/eslint.json index aa1e64b4a..2d02d5096 100644 --- a/config/eslint.json +++ b/config/eslint.json @@ -45,7 +45,7 @@ "no-div-regex": 1, "no-else-return": 1, "no-empty-function": 1, - "no-eq-null": 1, + "no-eq-null": 0, // used to test if not null and not undefined "no-eval": 1, "no-extend-native": 1, "no-extra-bind": 1, diff --git a/index.d.ts b/index.d.ts index d1e5f4893..49264665a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -211,13 +211,19 @@ export class Enum extends ReflectionObject { public comments: { [k: string]: string }; /** - * Creates an enum from JSON. + * Constructs an enum from an enum descriptor. * @param {string} name Enum name - * @param {Object.} json JSON object + * @param {EnumDescriptor} json Enum descriptor * @returns {Enum} Created enum * @throws {TypeError} If arguments are invalid */ - public static fromJSON(name: string, json: { [k: string]: any }): Enum; + public static fromJSON(name: string, json: EnumDescriptor): Enum; + + /** + * Converts this enum to an enum descriptor. + * @returns {EnumDescriptor} Enum descriptor + */ + public toJSON(): EnumDescriptor; /** * Adds a value to this enum. @@ -240,6 +246,18 @@ export class Enum extends ReflectionObject { public remove(name: string): Enum; } +/** + * Enum descriptor. + * @typedef EnumDescriptor + * @type {Object} + * @property {Object.} values Enum values + * @property {Object.} [options] Enum options + */ +type EnumDescriptor = { + values: { [k: string]: number }; + options?: { [k: string]: any }; +}; + /** * Constructs a new message field instance. Note that {@link MapField|map fields} have their own class. * @classdesc Reflected message field. @@ -379,13 +397,19 @@ export class Field extends ReflectionObject { public readonly packed: boolean; /** - * Constructs a field from JSON. + * Constructs a field from a field descriptor. * @param {string} name Field name - * @param {Object.} json JSON object + * @param {FieldDescriptor} json Field descriptor * @returns {Field} Created field * @throws {TypeError} If arguments are invalid */ - public static fromJSON(name: string, json: { [k: string]: any }): Field; + public static fromJSON(name: string, json: FieldDescriptor): Field; + + /** + * Converts this field to a field descriptor. + * @returns {FieldDescriptor} Field descriptor + */ + public toJSON(): FieldDescriptor; /** * Resolves this field's type references. @@ -395,6 +419,40 @@ export class Field extends ReflectionObject { public resolve(): Field; } +/** + * Field descriptor. + * @typedef FieldDescriptor + * @type {Object} + * @property {string} [rule="optional"] Field rule + * @property {string} type Field type + * @property {number} id Field id + * @property {Object.} [options] Field options + */ +type FieldDescriptor = { + rule?: string; + type: string; + id: number; + options?: { [k: string]: any }; +}; + +/** + * Extension field descriptor. + * @typedef ExtensionFieldDescriptor + * @type {Object} + * @property {string} [rule="optional"] Field rule + * @property {string} type Field type + * @property {number} id Field id + * @property {string} extend Extended type + * @property {Object.} [options] Field options + */ +type ExtensionFieldDescriptor = { + rule?: string; + type: string; + id: number; + extend: string; + options?: { [k: string]: any }; +}; + /** * Debugging utility functions. Only present in debug builds. * @namespace @@ -545,15 +603,55 @@ export class MapField extends Field { public resolvedKeyType: ReflectionObject; /** - * Constructs a map field from JSON. + * Constructs a map field from a map field descriptor. * @param {string} name Field name - * @param {Object.} json JSON object + * @param {MapFieldDescriptor} json Map field descriptor * @returns {MapField} Created map field * @throws {TypeError} If arguments are invalid */ - public static fromJSON(name: string, json: { [k: string]: any }): MapField; + public static fromJSON(name: string, json: MapFieldDescriptor): MapField; + + /** + * Converts this map field to a map field descriptor. + * @returns {MapFieldDescriptor} Map field descriptor + */ + public toJSON(): MapFieldDescriptor; } +/** + * Map field descriptor. + * @typedef MapFieldDescriptor + * @type {Object} + * @property {string} keyType Key type + * @property {string} type Value type + * @property {number} id Field id + * @property {Object.} [options] Field options + */ +type MapFieldDescriptor = { + keyType: string; + type: string; + id: number; + options?: { [k: string]: any }; +}; + +/** + * Extension map field descriptor. + * @typedef ExtensionMapFieldDescriptor + * @type {Object} + * @property {string} keyType Key type + * @property {string} type Value type + * @property {number} id Field id + * @property {string} extend Extended type + * @property {Object.} [options] Field options + */ +type ExtensionMapFieldDescriptor = { + keyType: string; + type: string; + id: number; + extend: string; + options?: { [k: string]: any }; +}; + /** * Constructs a new message instance. * @classdesc Abstract runtime message. @@ -740,15 +838,40 @@ export class Method extends ReflectionObject { public resolvedResponseType: Type; /** - * Constructs a service method from JSON. + * Constructs a method from a method descriptor. * @param {string} name Method name - * @param {Object.} json JSON object + * @param {MethodDescriptor} json Method descriptor * @returns {Method} Created method * @throws {TypeError} If arguments are invalid */ - public static fromJSON(name: string, json: { [k: string]: any }): Method; + public static fromJSON(name: string, json: MethodDescriptor): Method; + + /** + * Converts this method to a method descriptor. + * @returns {MethodDescriptor} + */ + public toJSON(): MethodDescriptor; } +/** + * @typedef MethodDescriptor + * @type {Object} + * @property {string} [type="rpc"] Method type + * @property {string} requestType Request type + * @property {string} responseType Response type + * @property {boolean} [requestStream=false] Whether requests are streamed + * @property {boolean} [responseStream=false] Whether responses are streamed + * @property {Object.} [options] Method options + */ +type MethodDescriptor = { + type?: string; + requestType: string; + responseType: string; + requestStream?: boolean; + responseStream?: boolean; + options?: { [k: string]: any }; +}; + /** * Constructs a new namespace instance. * @name Namespace @@ -819,11 +942,17 @@ export abstract class NamespaceBase extends ReflectionObject { public readonly nestedArray: ReflectionObject[]; /** - * Adds nested elements to this namespace from JSON. - * @param {Object.} nestedJson Nested JSON + * Converts this namespace to a namespace descriptor. + * @returns {NamespaceDescriptor} Namespace descriptor + */ + public toJSON(): NamespaceDescriptor; + + /** + * Adds nested objects to this namespace from nested object descriptors. + * @param {Object.} nestedJson Any nested object descriptors * @returns {Namespace} `this` */ - public addJSON(nestedJson: { [k: string]: any }): Namespace; + public addJSON(nestedJson: { [k: string]: AnyNestedDescriptor }): Namespace; /** * Gets the nested object of the specified name. @@ -921,6 +1050,25 @@ export abstract class NamespaceBase extends ReflectionObject { public lookupEnum(path: (string|string[])): { [k: string]: number }; } +/** + * Any nested object descriptor. + * @typedef AnyNestedDescriptor + * @type {EnumDescriptor|TypeDescriptor|ServiceDescriptor|ExtensionFieldDescriptor|ExtensionMapFieldDescriptor} + */ +type AnyNestedDescriptor = (EnumDescriptor|TypeDescriptor|ServiceDescriptor|ExtensionFieldDescriptor|ExtensionMapFieldDescriptor); + +/** + * Namespace descriptor. + * @typedef NamespaceDescriptor + * @type {Object} + * @property {Object.} [options] Namespace options + * @property {Object.} [nested] Nested object descriptors + */ +type NamespaceDescriptor = { + options?: { [k: string]: any }; + nested?: { [k: string]: AnyNestedDescriptor }; +}; + /** * Constructs a new reflection object instance. * @classdesc Base class of all reflection objects. @@ -984,8 +1132,8 @@ export abstract class ReflectionObject { public readonly fullName: string; /** - * Converts this reflection object to its JSON representation. - * @returns {Object.} JSON object + * Converts this reflection object to its descriptor representation. + * @returns {Object.} Descriptor * @abstract */ public toJSON(): { [k: string]: any }; @@ -1077,13 +1225,19 @@ export class OneOf extends ReflectionObject { public readonly fieldsArray: Field[]; /** - * Constructs a oneof from JSON. + * Constructs a oneof from a oneof descriptor. * @param {string} name Oneof name - * @param {Object.} json JSON object - * @returns {MapField} Created oneof + * @param {OneOfDescriptor} json Oneof descriptor + * @returns {OneOf} Created oneof * @throws {TypeError} If arguments are invalid */ - public static fromJSON(name: string, json: { [k: string]: any }): MapField; + public static fromJSON(name: string, json: OneOfDescriptor): OneOf; + + /** + * Converts this oneof to a oneof descriptor. + * @returns {OneOfDescriptor} Oneof descriptor + */ + public toJSON(): OneOfDescriptor; /** * Adds a field to this oneof and removes it from its current parent, if any. @@ -1100,6 +1254,18 @@ export class OneOf extends ReflectionObject { public remove(field: Field): OneOf; } +/** + * Oneof descriptor. + * @typedef OneOfDescriptor + * @type {Object} + * @property {Array.} oneof Oneof field names + * @property {Object.} [options] Oneof options + */ +type OneOfDescriptor = { + oneof: string[]; + options?: { [k: string]: any }; +}; + /** * Result object returned from {@link parse}. * @typedef ParserResult @@ -1371,12 +1537,12 @@ export class Root extends NamespaceBase { public files: string[]; /** - * Loads a JSON definition into a root namespace. - * @param {Object.} json JSON definition + * Loads a namespace descriptor into a root namespace. + * @param {NamespaceDescriptor} json Nameespace descriptor * @param {Root} [root] Root namespace, defaults to create a new one if omitted * @returns {Root} Root namespace */ - public static fromJSON(json: { [k: string]: any }, root?: Root): Root; + public static fromJSON(json: NamespaceDescriptor, root?: Root): Root; /** * Resolves the path of an imported file, relative to the importing origin. @@ -1582,13 +1748,19 @@ export class Service extends NamespaceBase { public methods: { [k: string]: Method }; /** - * Constructs a service from JSON. + * Constructs a service from a service descriptor. * @param {string} name Service name - * @param {Object.} json JSON object + * @param {ServiceDescriptor} json Service descriptor * @returns {Service} Created service * @throws {TypeError} If arguments are invalid */ - public static fromJSON(name: string, json: { [k: string]: any }): Service; + public static fromJSON(name: string, json: ServiceDescriptor): Service; + + /** + * Converts this service to a service descriptor. + * @returns {ServiceDescriptor} Service descriptor + */ + public toJSON(): ServiceDescriptor; /** * Methods of this service as an array for iteration. @@ -1608,6 +1780,20 @@ export class Service extends NamespaceBase { public create(rpcImpl: RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): rpc.Service; } +/** + * Service descriptor. + * @typedef ServiceDescriptor + * @type {Object} + * @property {Object.} [options] Service options + * @property {Object.} methods Method descriptors + * @property {Object.} [nested] Nested object descriptors + */ +type ServiceDescriptor = { + options?: { [k: string]: any }; + methods: { [k: string]: MethodDescriptor }; + nested?: { [k: string]: AnyNestedDescriptor }; +}; + /** * Handle object returned from {@link tokenize}. * @typedef {Object.} TokenizerHandle @@ -1648,14 +1834,6 @@ export class Type extends NamespaceBase { */ constructor(name: string, options?: { [k: string]: any }); - /** - * Creates a type from JSON. - * @param {string} name Message name - * @param {Object.} json JSON object - * @returns {Type} Created message type - */ - public static fromJSON(name: string, json: { [k: string]: any }): Type; - /** * Message fields. * @type {Object.} @@ -1712,6 +1890,20 @@ export class Type extends NamespaceBase { */ public ctor: Class; + /** + * Creates a message type from a message type descriptor. + * @param {string} name Message name + * @param {TypeDescriptor} json Message type descriptor + * @returns {Type} Created message type + */ + public static fromJSON(name: string, json: TypeDescriptor): Type; + + /** + * Converts this message type to a message type descriptor. + * @returns {TypeDescriptor} Message type descriptor + */ + public toJSON(): TypeDescriptor; + /** * Adds a nested object to this type. * @param {ReflectionObject} object Nested object to add @@ -1824,6 +2016,28 @@ export class Type extends NamespaceBase { public toObject(message: Message, options?: ConversionOptions): { [k: string]: any }; } +/** + * Message type descriptor. + * @typedef TypeDescriptor + * @type {Object} + * @property {Object.} [options] Message type options + * @property {Object.} [oneofs] Oneof descriptors + * @property {Object.} fields Field descriptors + * @property {number[][]} [extensions] Extension ranges + * @property {number[][]} [reserved] Reserved ranges + * @property {boolean} [group=false] Whether a legacy group or not + * @property {Object.} [nested] Nested object descriptors + */ +type TypeDescriptor = { + options?: { [k: string]: any }; + oneofs?: { [k: string]: OneOfDescriptor }; + fields: { [k: string]: FieldDescriptor }; + extensions?: number[][]; + reserved?: number[][]; + group?: boolean; + nested?: { [k: string]: AnyNestedDescriptor }; +}; + /** * Conversion options as used by {@link Type#toObject} and {@link Message.toObject}. * @typedef ConversionOptions diff --git a/src/enum.js b/src/enum.js index fb4b48e7a..972e004c3 100644 --- a/src/enum.js +++ b/src/enum.js @@ -50,9 +50,17 @@ function Enum(name, values, options) { } /** - * Creates an enum from JSON. + * Enum descriptor. + * @typedef EnumDescriptor + * @type {Object} + * @property {Object.} values Enum values + * @property {Object.} [options] Enum options + */ + +/** + * Constructs an enum from an enum descriptor. * @param {string} name Enum name - * @param {Object.} json JSON object + * @param {EnumDescriptor} json Enum descriptor * @returns {Enum} Created enum * @throws {TypeError} If arguments are invalid */ @@ -61,7 +69,8 @@ Enum.fromJSON = function fromJSON(name, json) { }; /** - * @override + * Converts this enum to an enum descriptor. + * @returns {EnumDescriptor} Enum descriptor */ Enum.prototype.toJSON = function toJSON() { return { diff --git a/src/field.js b/src/field.js index b07c9aa5e..d69706eed 100644 --- a/src/field.js +++ b/src/field.js @@ -184,9 +184,30 @@ Field.prototype.setOption = function setOption(name, value, ifNotSet) { }; /** - * Constructs a field from JSON. + * Field descriptor. + * @typedef FieldDescriptor + * @type {Object} + * @property {string} [rule="optional"] Field rule + * @property {string} type Field type + * @property {number} id Field id + * @property {Object.} [options] Field options + */ + +/** + * Extension field descriptor. + * @typedef ExtensionFieldDescriptor + * @type {Object} + * @property {string} [rule="optional"] Field rule + * @property {string} type Field type + * @property {number} id Field id + * @property {string} extend Extended type + * @property {Object.} [options] Field options + */ + +/** + * Constructs a field from a field descriptor. * @param {string} name Field name - * @param {Object.} json JSON object + * @param {FieldDescriptor} json Field descriptor * @returns {Field} Created field * @throws {TypeError} If arguments are invalid */ @@ -195,7 +216,8 @@ Field.fromJSON = function fromJSON(name, json) { }; /** - * @override + * Converts this field to a field descriptor. + * @returns {FieldDescriptor} Field descriptor */ Field.prototype.toJSON = function toJSON() { return { diff --git a/src/mapfield.js b/src/mapfield.js index d3c68741a..f17b7dbf7 100644 --- a/src/mapfield.js +++ b/src/mapfield.js @@ -43,9 +43,30 @@ function MapField(name, id, keyType, type, options) { } /** - * Constructs a map field from JSON. + * Map field descriptor. + * @typedef MapFieldDescriptor + * @type {Object} + * @property {string} keyType Key type + * @property {string} type Value type + * @property {number} id Field id + * @property {Object.} [options] Field options + */ + +/** + * Extension map field descriptor. + * @typedef ExtensionMapFieldDescriptor + * @type {Object} + * @property {string} keyType Key type + * @property {string} type Value type + * @property {number} id Field id + * @property {string} extend Extended type + * @property {Object.} [options] Field options + */ + +/** + * Constructs a map field from a map field descriptor. * @param {string} name Field name - * @param {Object.} json JSON object + * @param {MapFieldDescriptor} json Map field descriptor * @returns {MapField} Created map field * @throws {TypeError} If arguments are invalid */ @@ -54,7 +75,8 @@ MapField.fromJSON = function fromJSON(name, json) { }; /** - * @override + * Converts this map field to a map field descriptor. + * @returns {MapFieldDescriptor} Map field descriptor */ MapField.prototype.toJSON = function toJSON() { return { diff --git a/src/method.js b/src/method.js index 9541ea148..e09c8b111 100644 --- a/src/method.js +++ b/src/method.js @@ -89,9 +89,20 @@ function Method(name, type, requestType, responseType, requestStream, responseSt } /** - * Constructs a service method from JSON. + * @typedef MethodDescriptor + * @type {Object} + * @property {string} [type="rpc"] Method type + * @property {string} requestType Request type + * @property {string} responseType Response type + * @property {boolean} [requestStream=false] Whether requests are streamed + * @property {boolean} [responseStream=false] Whether responses are streamed + * @property {Object.} [options] Method options + */ + +/** + * Constructs a method from a method descriptor. * @param {string} name Method name - * @param {Object.} json JSON object + * @param {MethodDescriptor} json Method descriptor * @returns {Method} Created method * @throws {TypeError} If arguments are invalid */ @@ -100,7 +111,8 @@ Method.fromJSON = function fromJSON(name, json) { }; /** - * @override + * Converts this method to a method descriptor. + * @returns {MethodDescriptor} Method descriptor */ Method.prototype.toJSON = function toJSON() { return { diff --git a/src/namespace.js b/src/namespace.js index 4872ae37a..03f3bdae5 100644 --- a/src/namespace.js +++ b/src/namespace.js @@ -98,7 +98,22 @@ Object.defineProperty(Namespace.prototype, "nestedArray", { }); /** - * @override + * Any nested object descriptor. + * @typedef AnyNestedDescriptor + * @type {EnumDescriptor|TypeDescriptor|ServiceDescriptor|ExtensionFieldDescriptor|ExtensionMapFieldDescriptor} + */ + +/** + * Namespace descriptor. + * @typedef NamespaceDescriptor + * @type {Object} + * @property {Object.} [options] Namespace options + * @property {Object.} [nested] Nested object descriptors + */ + +/** + * Converts this namespace to a namespace descriptor. + * @returns {NamespaceDescriptor} Namespace descriptor */ Namespace.prototype.toJSON = function toJSON() { return { @@ -108,8 +123,8 @@ Namespace.prototype.toJSON = function toJSON() { }; /** - * Adds nested elements to this namespace from JSON. - * @param {Object.} nestedJson Nested JSON + * Adds nested objects to this namespace from nested object descriptors. + * @param {Object.} nestedJson Any nested object descriptors * @returns {Namespace} `this` */ Namespace.prototype.addJSON = function addJSON(nestedJson) { diff --git a/src/object.js b/src/object.js index 82869974b..d36d4b525 100644 --- a/src/object.js +++ b/src/object.js @@ -97,8 +97,8 @@ Object.defineProperties(ReflectionObject.prototype, { }); /** - * Converts this reflection object to its JSON representation. - * @returns {Object.} JSON object + * Converts this reflection object to its descriptor representation. + * @returns {Object.} Descriptor * @abstract */ ReflectionObject.prototype.toJSON = /* istanbul ignore next */ function toJSON() { diff --git a/src/oneof.js b/src/oneof.js index 10fe734bd..bf8f49ae8 100644 --- a/src/oneof.js +++ b/src/oneof.js @@ -42,10 +42,18 @@ function OneOf(name, fieldNames, options) { } /** - * Constructs a oneof from JSON. + * Oneof descriptor. + * @typedef OneOfDescriptor + * @type {Object} + * @property {Array.} oneof Oneof field names + * @property {Object.} [options] Oneof options + */ + +/** + * Constructs a oneof from a oneof descriptor. * @param {string} name Oneof name - * @param {Object.} json JSON object - * @returns {MapField} Created oneof + * @param {OneOfDescriptor} json Oneof descriptor + * @returns {OneOf} Created oneof * @throws {TypeError} If arguments are invalid */ OneOf.fromJSON = function fromJSON(name, json) { @@ -53,7 +61,8 @@ OneOf.fromJSON = function fromJSON(name, json) { }; /** - * @override + * Converts this oneof to a oneof descriptor. + * @returns {OneOfDescriptor} Oneof descriptor */ OneOf.prototype.toJSON = function toJSON() { return { diff --git a/src/root.js b/src/root.js index d02d658f6..f7d0af149 100644 --- a/src/root.js +++ b/src/root.js @@ -37,8 +37,8 @@ function Root(options) { } /** - * Loads a JSON definition into a root namespace. - * @param {Object.} json JSON definition + * Loads a namespace descriptor into a root namespace. + * @param {NamespaceDescriptor} json Nameespace descriptor * @param {Root} [root] Root namespace, defaults to create a new one if omitted * @returns {Root} Root namespace */ diff --git a/src/service.js b/src/service.js index 9f250dcd5..afc5d2197 100644 --- a/src/service.js +++ b/src/service.js @@ -36,9 +36,18 @@ function Service(name, options) { } /** - * Constructs a service from JSON. + * Service descriptor. + * @typedef ServiceDescriptor + * @type {Object} + * @property {Object.} [options] Service options + * @property {Object.} methods Method descriptors + * @property {Object.} [nested] Nested object descriptors + */ + +/** + * Constructs a service from a service descriptor. * @param {string} name Service name - * @param {Object.} json JSON object + * @param {ServiceDescriptor} json Service descriptor * @returns {Service} Created service * @throws {TypeError} If arguments are invalid */ @@ -48,9 +57,24 @@ Service.fromJSON = function fromJSON(name, json) { if (json.methods) for (var names = Object.keys(json.methods), i = 0; i < names.length; ++i) service.add(Method.fromJSON(names[i], json.methods[names[i]])); + if (json.nested) + service.addJSON(json.nested); return service; }; +/** + * Converts this service to a service descriptor. + * @returns {ServiceDescriptor} Service descriptor + */ +Service.prototype.toJSON = function toJSON() { + var inherited = Namespace.prototype.toJSON.call(this); + return { + options : inherited && inherited.options || undefined, + methods : Namespace.arrayToJSON(this.methodsArray) || /* istanbul ignore next */ {}, + nested : inherited && inherited.nested || undefined + }; +}; + /** * Methods of this service as an array for iteration. * @name Service#methodsArray @@ -68,18 +92,6 @@ function clearCache(service) { return service; } -/** - * @override - */ -Service.prototype.toJSON = function toJSON() { - var inherited = Namespace.prototype.toJSON.call(this); - return { - options : inherited && inherited.options || undefined, - methods : Namespace.arrayToJSON(this.methodsArray) || /* istanbul ignore next */ {}, - nested : inherited && inherited.nested || undefined - }; -}; - /** * @override */ diff --git a/src/type.js b/src/type.js index d872dacab..639cd6efe 100644 --- a/src/type.js +++ b/src/type.js @@ -20,51 +20,6 @@ var Enum = require("./enum"), verifier = require("./verifier"), converter = require("./converter"); -/** - * Creates a type from JSON. - * @param {string} name Message name - * @param {Object.} json JSON object - * @returns {Type} Created message type - */ -Type.fromJSON = function fromJSON(name, json) { - var type = new Type(name, json.options); - type.extensions = json.extensions; - type.reserved = json.reserved; - var names = Object.keys(json.fields), - i = 0; - for (; i < names.length; ++i) - type.add( - ( typeof json.fields[names[i]].keyType !== "undefined" - ? MapField.fromJSON - : Field.fromJSON )(names[i], json.fields[names[i]]) - ); - if (json.oneofs) - for (names = Object.keys(json.oneofs), i = 0; i < names.length; ++i) - type.add(OneOf.fromJSON(names[i], json.oneofs[names[i]])); - if (json.nested) - for (names = Object.keys(json.nested), i = 0; i < names.length; ++i) { - var nested = json.nested[names[i]]; - type.add( // most to least likely - ( nested.id !== undefined - ? Field.fromJSON - : nested.fields !== undefined - ? Type.fromJSON - : nested.values !== undefined - ? Enum.fromJSON - : nested.methods !== undefined - ? Service.fromJSON - : Namespace.fromJSON )(names[i], nested) - ); - } - if (json.extensions && json.extensions.length) - type.extensions = json.extensions; - if (json.reserved && json.reserved.length) - type.reserved = json.reserved; - if (json.group) - type.group = true; - return type; -}; - /** * Constructs a new reflected message type instance. * @classdesc Reflected message type. @@ -217,7 +172,66 @@ function clearCache(type) { } /** - * @override + * Message type descriptor. + * @typedef TypeDescriptor + * @type {Object} + * @property {Object.} [options] Message type options + * @property {Object.} [oneofs] Oneof descriptors + * @property {Object.} fields Field descriptors + * @property {number[][]} [extensions] Extension ranges + * @property {number[][]} [reserved] Reserved ranges + * @property {boolean} [group=false] Whether a legacy group or not + * @property {Object.} [nested] Nested object descriptors + */ + +/** + * Creates a message type from a message type descriptor. + * @param {string} name Message name + * @param {TypeDescriptor} json Message type descriptor + * @returns {Type} Created message type + */ +Type.fromJSON = function fromJSON(name, json) { + var type = new Type(name, json.options); + type.extensions = json.extensions; + type.reserved = json.reserved; + var names = Object.keys(json.fields), + i = 0; + for (; i < names.length; ++i) + type.add( + ( typeof json.fields[names[i]].keyType !== "undefined" + ? MapField.fromJSON + : Field.fromJSON )(names[i], json.fields[names[i]]) + ); + if (json.oneofs) + for (names = Object.keys(json.oneofs), i = 0; i < names.length; ++i) + type.add(OneOf.fromJSON(names[i], json.oneofs[names[i]])); + if (json.nested) + for (names = Object.keys(json.nested), i = 0; i < names.length; ++i) { + var nested = json.nested[names[i]]; + type.add( // most to least likely + ( nested.id !== undefined + ? Field.fromJSON + : nested.fields !== undefined + ? Type.fromJSON + : nested.values !== undefined + ? Enum.fromJSON + : nested.methods !== undefined + ? Service.fromJSON + : Namespace.fromJSON )(names[i], nested) + ); + } + if (json.extensions && json.extensions.length) + type.extensions = json.extensions; + if (json.reserved && json.reserved.length) + type.reserved = json.reserved; + if (json.group) + type.group = true; + return type; +}; + +/** + * Converts this message type to a message type descriptor. + * @returns {TypeDescriptor} Message type descriptor */ Type.prototype.toJSON = function toJSON() { var inherited = Namespace.prototype.toJSON.call(this); diff --git a/src/util/minimal.js b/src/util/minimal.js index b03d80cda..48f9ad42b 100644 --- a/src/util/minimal.js +++ b/src/util/minimal.js @@ -71,15 +71,15 @@ util.isObject = function isObject(value) { }; /** - * Checks if a property on a message is considered present. + * Checks if a property on a message is considered to be present. * @param {Object} obj Plain object or message instance * @param {string} prop Property name - * @returns {boolean} `true` if considered present, otherwise `false` + * @returns {boolean} `true` if considered to be present, otherwise `false` */ -util.isset = function isset(message, prop) { +util.isset = function isset(obj, prop) { var value = obj[prop]; - if (value != null && obj.hasOwnProperty(prop)) - return typeof value !== 'object' || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0; + if (value != null && obj.hasOwnProperty(prop)) // eslint-disable-line eqeqeq, no-prototype-builtins + return typeof value !== "object" || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0; return false; };