HarshvardhanCn01/Voice-Assistant
0
1"use strict";2module.exports = Namespace;3 4// extends ReflectionObject5var ReflectionObject = require("./object");6((Namespace.prototype = Object.create(ReflectionObject.prototype)).constructor = Namespace).className = "Namespace";7 8var Field = require("./field"),9 util = require("./util"),10 OneOf = require("./oneof");11 12var Type, // cyclic13 Service,14 Enum;15 16/**17 * Constructs a new namespace instance.18 * @name Namespace19 * @classdesc Reflected namespace.20 * @extends NamespaceBase21 * @constructor22 * @param {string} name Namespace name23 * @param {Object.<string,*>} [options] Declared options24 */25 26/**27 * Constructs a namespace from JSON.28 * @memberof Namespace29 * @function30 * @param {string} name Namespace name31 * @param {Object.<string,*>} json JSON object32 * @returns {Namespace} Created namespace33 * @throws {TypeError} If arguments are invalid34 */35Namespace.fromJSON = function fromJSON(name, json) {36 return new Namespace(name, json.options).addJSON(json.nested);37};38 39/**40 * Converts an array of reflection objects to JSON.41 * @memberof Namespace42 * @param {ReflectionObject[]} array Object array43 * @param {IToJSONOptions} [toJSONOptions] JSON conversion options44 * @returns {Object.<string,*>|undefined} JSON object or `undefined` when array is empty45 */46function arrayToJSON(array, toJSONOptions) {47 if (!(array && array.length))48 return undefined;49 var obj = {};50 for (var i = 0; i < array.length; ++i)51 obj[array[i].name] = array[i].toJSON(toJSONOptions);52 return obj;53}54 55Namespace.arrayToJSON = arrayToJSON;56 57/**58 * Tests if the specified id is reserved.59 * @param {Array.<number[]|string>|undefined} reserved Array of reserved ranges and names60 * @param {number} id Id to test61 * @returns {boolean} `true` if reserved, otherwise `false`62 */63Namespace.isReservedId = function isReservedId(reserved, id) {64 if (reserved)65 for (var i = 0; i < reserved.length; ++i)66 if (typeof reserved[i] !== "string" && reserved[i][0] <= id && reserved[i][1] > id)67 return true;68 return false;69};70 71/**72 * Tests if the specified name is reserved.73 * @param {Array.<number[]|string>|undefined} reserved Array of reserved ranges and names74 * @param {string} name Name to test75 * @returns {boolean} `true` if reserved, otherwise `false`76 */77Namespace.isReservedName = function isReservedName(reserved, name) {78 if (reserved)79 for (var i = 0; i < reserved.length; ++i)80 if (reserved[i] === name)81 return true;82 return false;83};84 85/**86 * Not an actual constructor. Use {@link Namespace} instead.87 * @classdesc Base class of all reflection objects containing nested objects. This is not an actual class but here for the sake of having consistent type definitions.88 * @exports NamespaceBase89 * @extends ReflectionObject90 * @abstract91 * @constructor92 * @param {string} name Namespace name93 * @param {Object.<string,*>} [options] Declared options94 * @see {@link Namespace}95 */96function Namespace(name, options) {97 ReflectionObject.call(this, name, options);98 99 /**100 * Nested objects by name.101 * @type {Object.<string,ReflectionObject>|undefined}102 */103 this.nested = undefined; // toJSON104 105 /**106 * Cached nested objects as an array.107 * @type {ReflectionObject[]|null}108 * @private109 */110 this._nestedArray = null;111}112 113function clearCache(namespace) {114 namespace._nestedArray = null;115 return namespace;116}117 118/**119 * Nested objects of this namespace as an array for iteration.120 * @name NamespaceBase#nestedArray121 * @type {ReflectionObject[]}122 * @readonly123 */124Object.defineProperty(Namespace.prototype, "nestedArray", {125 get: function() {126 return this._nestedArray || (this._nestedArray = util.toArray(this.nested));127 }128});129 130/**131 * Namespace descriptor.132 * @interface INamespace133 * @property {Object.<string,*>} [options] Namespace options134 * @property {Object.<string,AnyNestedObject>} [nested] Nested object descriptors135 */136 137/**138 * Any extension field descriptor.139 * @typedef AnyExtensionField140 * @type {IExtensionField|IExtensionMapField}141 */142 143/**144 * Any nested object descriptor.145 * @typedef AnyNestedObject146 * @type {IEnum|IType|IService|AnyExtensionField|INamespace|IOneOf}147 */148 149/**150 * Converts this namespace to a namespace descriptor.151 * @param {IToJSONOptions} [toJSONOptions] JSON conversion options152 * @returns {INamespace} Namespace descriptor153 */154Namespace.prototype.toJSON = function toJSON(toJSONOptions) {155 return util.toObject([156 "options" , this.options,157 "nested" , arrayToJSON(this.nestedArray, toJSONOptions)158 ]);159};160 161/**162 * Adds nested objects to this namespace from nested object descriptors.163 * @param {Object.<string,AnyNestedObject>} nestedJson Any nested object descriptors164 * @returns {Namespace} `this`165 */166Namespace.prototype.addJSON = function addJSON(nestedJson) {167 var ns = this;168 /* istanbul ignore else */169 if (nestedJson) {170 for (var names = Object.keys(nestedJson), i = 0, nested; i < names.length; ++i) {171 nested = nestedJson[names[i]];172 ns.add( // most to least likely173 ( nested.fields !== undefined174 ? Type.fromJSON175 : nested.values !== undefined176 ? Enum.fromJSON177 : nested.methods !== undefined178 ? Service.fromJSON179 : nested.id !== undefined180 ? Field.fromJSON181 : Namespace.fromJSON )(names[i], nested)182 );183 }184 }185 return this;186};187 188/**189 * Gets the nested object of the specified name.190 * @param {string} name Nested object name191 * @returns {ReflectionObject|null} The reflection object or `null` if it doesn't exist192 */193Namespace.prototype.get = function get(name) {194 return this.nested && this.nested[name]195 || null;196};197 198/**199 * Gets the values of the nested {@link Enum|enum} of the specified name.200 * This methods differs from {@link Namespace#get|get} in that it returns an enum's values directly and throws instead of returning `null`.201 * @param {string} name Nested enum name202 * @returns {Object.<string,number>} Enum values203 * @throws {Error} If there is no such enum204 */205Namespace.prototype.getEnum = function getEnum(name) {206 if (this.nested && this.nested[name] instanceof Enum)207 return this.nested[name].values;208 throw Error("no such enum: " + name);209};210 211/**212 * Adds a nested object to this namespace.213 * @param {ReflectionObject} object Nested object to add214 * @returns {Namespace} `this`215 * @throws {TypeError} If arguments are invalid216 * @throws {Error} If there is already a nested object with this name217 */218Namespace.prototype.add = function add(object) {219 220 if (!(object instanceof Field && object.extend !== undefined || object instanceof Type || object instanceof OneOf || object instanceof Enum || object instanceof Service || object instanceof Namespace))221 throw TypeError("object must be a valid nested object");222 223 if (!this.nested)224 this.nested = {};225 else {226 var prev = this.get(object.name);227 if (prev) {228 if (prev instanceof Namespace && object instanceof Namespace && !(prev instanceof Type || prev instanceof Service)) {229 // replace plain namespace but keep existing nested elements and options230 var nested = prev.nestedArray;231 for (var i = 0; i < nested.length; ++i)232 object.add(nested[i]);233 this.remove(prev);234 if (!this.nested)235 this.nested = {};236 object.setOptions(prev.options, true);237 238 } else239 throw Error("duplicate name '" + object.name + "' in " + this);240 }241 }242 this.nested[object.name] = object;243 object.onAdd(this);244 return clearCache(this);245};246 247/**248 * Removes a nested object from this namespace.249 * @param {ReflectionObject} object Nested object to remove250 * @returns {Namespace} `this`251 * @throws {TypeError} If arguments are invalid252 * @throws {Error} If `object` is not a member of this namespace253 */254Namespace.prototype.remove = function remove(object) {255 256 if (!(object instanceof ReflectionObject))257 throw TypeError("object must be a ReflectionObject");258 if (object.parent !== this)259 throw Error(object + " is not a member of " + this);260 261 delete this.nested[object.name];262 if (!Object.keys(this.nested).length)263 this.nested = undefined;264 265 object.onRemove(this);266 return clearCache(this);267};268 269/**270 * Defines additial namespaces within this one if not yet existing.271 * @param {string|string[]} path Path to create272 * @param {*} [json] Nested types to create from JSON273 * @returns {Namespace} Pointer to the last namespace created or `this` if path is empty274 */275Namespace.prototype.define = function define(path, json) {276 277 if (util.isString(path))278 path = path.split(".");279 else if (!Array.isArray(path))280 throw TypeError("illegal path");281 if (path && path.length && path[0] === "")282 throw Error("path must be relative");283 284 var ptr = this;285 while (path.length > 0) {286 var part = path.shift();287 if (ptr.nested && ptr.nested[part]) {288 ptr = ptr.nested[part];289 if (!(ptr instanceof Namespace))290 throw Error("path conflicts with non-namespace objects");291 } else292 ptr.add(ptr = new Namespace(part));293 }294 if (json)295 ptr.addJSON(json);296 return ptr;297};298 299/**300 * Resolves this namespace's and all its nested objects' type references. Useful to validate a reflection tree, but comes at a cost.301 * @returns {Namespace} `this`302 */303Namespace.prototype.resolveAll = function resolveAll() {304 var nested = this.nestedArray, i = 0;305 while (i < nested.length)306 if (nested[i] instanceof Namespace)307 nested[i++].resolveAll();308 else309 nested[i++].resolve();310 return this.resolve();311};312 313/**314 * Recursively looks up the reflection object matching the specified path in the scope of this namespace.315 * @param {string|string[]} path Path to look up316 * @param {*|Array.<*>} filterTypes Filter types, any combination of the constructors of `protobuf.Type`, `protobuf.Enum`, `protobuf.Service` etc.317 * @param {boolean} [parentAlreadyChecked=false] If known, whether the parent has already been checked318 * @returns {ReflectionObject|null} Looked up object or `null` if none could be found319 */320Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {321 322 /* istanbul ignore next */323 if (typeof filterTypes === "boolean") {324 parentAlreadyChecked = filterTypes;325 filterTypes = undefined;326 } else if (filterTypes && !Array.isArray(filterTypes))327 filterTypes = [ filterTypes ];328 329 if (util.isString(path) && path.length) {330 if (path === ".")331 return this.root;332 path = path.split(".");333 } else if (!path.length)334 return this;335 336 // Start at root if path is absolute337 if (path[0] === "")338 return this.root.lookup(path.slice(1), filterTypes);339 340 // Test if the first part matches any nested object, and if so, traverse if path contains more341 var found = this.get(path[0]);342 if (found) {343 if (path.length === 1) {344 if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)345 return found;346 } else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))347 return found;348 349 // Otherwise try each nested namespace350 } else351 for (var i = 0; i < this.nestedArray.length; ++i)352 if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i].lookup(path, filterTypes, true)))353 return found;354 355 // If there hasn't been a match, try again at the parent356 if (this.parent === null || parentAlreadyChecked)357 return null;358 return this.parent.lookup(path, filterTypes);359};360 361/**362 * Looks up the reflection object at the specified path, relative to this namespace.363 * @name NamespaceBase#lookup364 * @function365 * @param {string|string[]} path Path to look up366 * @param {boolean} [parentAlreadyChecked=false] Whether the parent has already been checked367 * @returns {ReflectionObject|null} Looked up object or `null` if none could be found368 * @variation 2369 */370// lookup(path: string, [parentAlreadyChecked: boolean])371 372/**373 * Looks up the {@link Type|type} at the specified path, relative to this namespace.374 * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.375 * @param {string|string[]} path Path to look up376 * @returns {Type} Looked up type377 * @throws {Error} If `path` does not point to a type378 */379Namespace.prototype.lookupType = function lookupType(path) {380 var found = this.lookup(path, [ Type ]);381 if (!found)382 throw Error("no such type: " + path);383 return found;384};385 386/**387 * Looks up the values of the {@link Enum|enum} at the specified path, relative to this namespace.388 * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.389 * @param {string|string[]} path Path to look up390 * @returns {Enum} Looked up enum391 * @throws {Error} If `path` does not point to an enum392 */393Namespace.prototype.lookupEnum = function lookupEnum(path) {394 var found = this.lookup(path, [ Enum ]);395 if (!found)396 throw Error("no such Enum '" + path + "' in " + this);397 return found;398};399 400/**401 * Looks up the {@link Type|type} or {@link Enum|enum} at the specified path, relative to this namespace.402 * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.403 * @param {string|string[]} path Path to look up404 * @returns {Type} Looked up type or enum405 * @throws {Error} If `path` does not point to a type or enum406 */407Namespace.prototype.lookupTypeOrEnum = function lookupTypeOrEnum(path) {408 var found = this.lookup(path, [ Type, Enum ]);409 if (!found)410 throw Error("no such Type or Enum '" + path + "' in " + this);411 return found;412};413 414/**415 * Looks up the {@link Service|service} at the specified path, relative to this namespace.416 * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.417 * @param {string|string[]} path Path to look up418 * @returns {Service} Looked up service419 * @throws {Error} If `path` does not point to a service420 */421Namespace.prototype.lookupService = function lookupService(path) {422 var found = this.lookup(path, [ Service ]);423 if (!found)424 throw Error("no such Service '" + path + "' in " + this);425 return found;426};427 428// Sets up cyclic dependencies (called in index-light)429Namespace._configure = function(Type_, Service_, Enum_) {430 Type = Type_;431 Service = Service_;432 Enum = Enum_;433};434 