basant307/AI_Governance_Project
048
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 * @param {number} [depth] Current nesting depth, defaults to `0`33 * @returns {Namespace} Created namespace34 * @throws {TypeError} If arguments are invalid35 */36Namespace.fromJSON = function fromJSON(name, json, depth) {37 depth = util.checkDepth(depth);38 return new Namespace(name, json.options).addJSON(json.nested, depth);39};40 41/**42 * Converts an array of reflection objects to JSON.43 * @memberof Namespace44 * @param {ReflectionObject[]} array Object array45 * @param {IToJSONOptions} [toJSONOptions] JSON conversion options46 * @returns {Object.<string,*>|undefined} JSON object or `undefined` when array is empty47 */48function arrayToJSON(array, toJSONOptions) {49 if (!(array && array.length))50 return undefined;51 var obj = {};52 for (var i = 0; i < array.length; ++i)53 obj[array[i].name] = array[i].toJSON(toJSONOptions);54 return obj;55}56 57Namespace.arrayToJSON = arrayToJSON;58 59/**60 * Tests if the specified id is reserved.61 * @param {Array.<number[]|string>|undefined} reserved Array of reserved ranges and names62 * @param {number} id Id to test63 * @returns {boolean} `true` if reserved, otherwise `false`64 */65Namespace.isReservedId = function isReservedId(reserved, id) {66 if (reserved)67 for (var i = 0; i < reserved.length; ++i)68 if (typeof reserved[i] !== "string" && reserved[i][0] <= id && reserved[i][1] > id)69 return true;70 return false;71};72 73/**74 * Tests if the specified name is reserved.75 * @param {Array.<number[]|string>|undefined} reserved Array of reserved ranges and names76 * @param {string} name Name to test77 * @returns {boolean} `true` if reserved, otherwise `false`78 */79Namespace.isReservedName = function isReservedName(reserved, name) {80 if (reserved)81 for (var i = 0; i < reserved.length; ++i)82 if (reserved[i] === name)83 return true;84 return false;85};86 87/**88 * Not an actual constructor. Use {@link Namespace} instead.89 * @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.90 * @exports NamespaceBase91 * @extends ReflectionObject92 * @abstract93 * @constructor94 * @param {string} name Namespace name95 * @param {Object.<string,*>} [options] Declared options96 * @see {@link Namespace}97 */98function Namespace(name, options) {99 ReflectionObject.call(this, name, options);100 101 /**102 * Nested objects by name.103 * @type {Object.<string,ReflectionObject>|undefined}104 */105 this.nested = undefined; // toJSON106 107 /**108 * Cached nested objects as an array.109 * @type {ReflectionObject[]|null}110 * @private111 */112 this._nestedArray = null;113 114 /**115 * Cache lookup calls for any objects contains anywhere under this namespace.116 * This drastically speeds up resolve for large cross-linked protos where the same117 * types are looked up repeatedly.118 * @type {Object.<string,ReflectionObject|null>}119 * @private120 */121 this._lookupCache = Object.create(null);122 123 /**124 * Whether or not objects contained in this namespace need feature resolution.125 * @type {boolean}126 * @protected127 */128 this._needsRecursiveFeatureResolution = true;129 130 /**131 * Whether or not objects contained in this namespace need a resolve.132 * @type {boolean}133 * @protected134 */135 this._needsRecursiveResolve = true;136}137 138function clearCache(namespace) {139 namespace._nestedArray = null;140 namespace._lookupCache = Object.create(null);141 142 // Also clear parent caches, since they include nested lookups.143 var parent = namespace;144 while(parent = parent.parent) {145 parent._lookupCache = Object.create(null);146 }147 return namespace;148}149 150/**151 * Nested objects of this namespace as an array for iteration.152 * @name NamespaceBase#nestedArray153 * @type {ReflectionObject[]}154 * @readonly155 */156Object.defineProperty(Namespace.prototype, "nestedArray", {157 get: function() {158 return this._nestedArray || (this._nestedArray = util.toArray(this.nested));159 }160});161 162/**163 * Namespace descriptor.164 * @interface INamespace165 * @property {Object.<string,*>} [options] Namespace options166 * @property {Object.<string,AnyNestedObject>} [nested] Nested object descriptors167 */168 169/**170 * Any extension field descriptor.171 * @typedef AnyExtensionField172 * @type {IExtensionField|IExtensionMapField}173 */174 175/**176 * Any nested object descriptor.177 * @typedef AnyNestedObject178 * @type {IEnum|IType|IService|AnyExtensionField|INamespace|IOneOf}179 */180 181/**182 * Converts this namespace to a namespace descriptor.183 * @param {IToJSONOptions} [toJSONOptions] JSON conversion options184 * @returns {INamespace} Namespace descriptor185 */186Namespace.prototype.toJSON = function toJSON(toJSONOptions) {187 return util.toObject([188 "options" , this.options,189 "nested" , arrayToJSON(this.nestedArray, toJSONOptions)190 ]);191};192 193/**194 * Adds nested objects to this namespace from nested object descriptors.195 * @param {Object.<string,AnyNestedObject>} nestedJson Any nested object descriptors196 * @param {number} [depth] Current nesting depth, defaults to `0`197 * @returns {Namespace} `this`198 */199Namespace.prototype.addJSON = function addJSON(nestedJson, depth) {200 depth = util.checkDepth(depth);201 var ns = this;202 /* istanbul ignore else */203 if (nestedJson) {204 for (var names = Object.keys(nestedJson), i = 0, nested; i < names.length; ++i) {205 nested = nestedJson[names[i]];206 ns.add( // most to least likely207 ( nested.fields !== undefined208 ? Type.fromJSON209 : nested.values !== undefined210 ? Enum.fromJSON211 : nested.methods !== undefined212 ? Service.fromJSON213 : nested.id !== undefined214 ? Field.fromJSON215 : Namespace.fromJSON )(names[i], nested, depth + 1)216 );217 }218 }219 return this;220};221 222/**223 * Gets the nested object of the specified name.224 * @param {string} name Nested object name225 * @returns {ReflectionObject|null} The reflection object or `null` if it doesn't exist226 */227Namespace.prototype.get = function get(name) {228 return this.nested && Object.prototype.hasOwnProperty.call(this.nested, name)229 ? this.nested[name]230 : null;231};232 233/**234 * Gets the values of the nested {@link Enum|enum} of the specified name.235 * This methods differs from {@link Namespace#get|get} in that it returns an enum's values directly and throws instead of returning `null`.236 * @param {string} name Nested enum name237 * @returns {Object.<string,number>} Enum values238 * @throws {Error} If there is no such enum239 */240Namespace.prototype.getEnum = function getEnum(name) {241 if (this.nested && Object.prototype.hasOwnProperty.call(this.nested, name) && this.nested[name] instanceof Enum)242 return this.nested[name].values;243 throw Error("no such enum: " + name);244};245 246/**247 * Adds a nested object to this namespace.248 * @param {ReflectionObject} object Nested object to add249 * @returns {Namespace} `this`250 * @throws {TypeError} If arguments are invalid251 * @throws {Error} If there is already a nested object with this name252 */253Namespace.prototype.add = function add(object) {254 255 if (!(object instanceof Field && object.extend !== undefined || object instanceof Type || object instanceof OneOf || object instanceof Enum || object instanceof Service || object instanceof Namespace))256 throw TypeError("object must be a valid nested object");257 258 if (object.name === "__proto__")259 return this;260 261 if (!this.nested)262 this.nested = {};263 else {264 var prev = this.get(object.name);265 if (prev) {266 if (prev instanceof Namespace && object instanceof Namespace && !(prev instanceof Type || prev instanceof Service)) {267 // replace plain namespace but keep existing nested elements and options268 var nested = prev.nestedArray;269 for (var i = 0; i < nested.length; ++i)270 object.add(nested[i]);271 this.remove(prev);272 if (!this.nested)273 this.nested = {};274 object.setOptions(prev.options, true);275 276 } else277 throw Error("duplicate name '" + object.name + "' in " + this);278 }279 }280 this.nested[object.name] = object;281 282 if (!(this instanceof Type || this instanceof Service || this instanceof Enum || this instanceof Field)) {283 // This is a package or a root namespace.284 if (!object._edition) {285 // Make sure that some edition is set if it hasn't already been specified.286 object._edition = object._defaultEdition;287 }288 }289 290 this._needsRecursiveFeatureResolution = true;291 this._needsRecursiveResolve = true;292 293 // Also clear parent caches, since they need to recurse down.294 var parent = this;295 while(parent = parent.parent) {296 parent._needsRecursiveFeatureResolution = true;297 parent._needsRecursiveResolve = true;298 }299 300 object.onAdd(this);301 return clearCache(this);302};303 304/**305 * Removes a nested object from this namespace.306 * @param {ReflectionObject} object Nested object to remove307 * @returns {Namespace} `this`308 * @throws {TypeError} If arguments are invalid309 * @throws {Error} If `object` is not a member of this namespace310 */311Namespace.prototype.remove = function remove(object) {312 313 if (!(object instanceof ReflectionObject))314 throw TypeError("object must be a ReflectionObject");315 if (object.parent !== this)316 throw Error(object + " is not a member of " + this);317 318 delete this.nested[object.name];319 if (!Object.keys(this.nested).length)320 this.nested = undefined;321 322 object.onRemove(this);323 return clearCache(this);324};325 326/**327 * Defines additial namespaces within this one if not yet existing.328 * @param {string|string[]} path Path to create329 * @param {*} [json] Nested types to create from JSON330 * @returns {Namespace} Pointer to the last namespace created or `this` if path is empty331 */332Namespace.prototype.define = function define(path, json) {333 334 if (util.isString(path))335 path = path.split(".");336 else if (!Array.isArray(path))337 throw TypeError("illegal path");338 if (path && path.length && path[0] === "")339 throw Error("path must be relative");340 if (path.length > util.recursionLimit)341 throw Error("max depth exceeded");342 343 var ptr = this;344 while (path.length > 0) {345 var part = path.shift();346 if (ptr.nested && ptr.nested[part]) {347 ptr = ptr.nested[part];348 if (!(ptr instanceof Namespace))349 throw Error("path conflicts with non-namespace objects");350 } else351 ptr.add(ptr = new Namespace(part));352 }353 if (json)354 ptr.addJSON(json);355 return ptr;356};357 358/**359 * Resolves this namespace's and all its nested objects' type references. Useful to validate a reflection tree, but comes at a cost.360 * @returns {Namespace} `this`361 */362Namespace.prototype.resolveAll = function resolveAll() {363 if (!this._needsRecursiveResolve) return this;364 365 this._resolveFeaturesRecursive(this._edition);366 367 var nested = this.nestedArray, i = 0;368 this.resolve();369 while (i < nested.length)370 if (nested[i] instanceof Namespace)371 nested[i++].resolveAll();372 else373 nested[i++].resolve();374 this._needsRecursiveResolve = false;375 return this;376};377 378/**379 * @override380 */381Namespace.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursive(edition) {382 if (!this._needsRecursiveFeatureResolution) return this;383 this._needsRecursiveFeatureResolution = false;384 385 edition = this._edition || edition;386 387 ReflectionObject.prototype._resolveFeaturesRecursive.call(this, edition);388 this.nestedArray.forEach(nested => {389 nested._resolveFeaturesRecursive(edition);390 });391 return this;392};393 394/**395 * Recursively looks up the reflection object matching the specified path in the scope of this namespace.396 * @param {string|string[]} path Path to look up397 * @param {*|Array.<*>} filterTypes Filter types, any combination of the constructors of `protobuf.Type`, `protobuf.Enum`, `protobuf.Service` etc.398 * @param {boolean} [parentAlreadyChecked=false] If known, whether the parent has already been checked399 * @returns {ReflectionObject|null} Looked up object or `null` if none could be found400 */401Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {402 /* istanbul ignore next */403 if (typeof filterTypes === "boolean") {404 parentAlreadyChecked = filterTypes;405 filterTypes = undefined;406 } else if (filterTypes && !Array.isArray(filterTypes))407 filterTypes = [ filterTypes ];408 409 if (util.isString(path) && path.length) {410 if (path === ".")411 return this.root;412 path = path.split(".");413 } else if (!path.length)414 return this;415 416 var flatPath = path.join(".");417 418 // Start at root if path is absolute419 if (path[0] === "")420 return this.root.lookup(path.slice(1), filterTypes);421 422 // Early bailout for objects with matching absolute paths423 var found = this.root._fullyQualifiedObjects && this.root._fullyQualifiedObjects["." + flatPath];424 if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {425 return found;426 }427 428 // Do a regular lookup at this namespace and below429 found = this._lookupImpl(path, flatPath);430 if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {431 return found;432 }433 434 if (parentAlreadyChecked)435 return null;436 437 // If there hasn't been a match, walk up the tree and look more broadly438 var current = this;439 while (current.parent) {440 found = current.parent._lookupImpl(path, flatPath);441 if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {442 return found;443 }444 current = current.parent;445 }446 return null;447};448 449/**450 * Internal helper for lookup that handles searching just at this namespace and below along with caching.451 * @param {string[]} path Path to look up452 * @param {string} flatPath Flattened version of the path to use as a cache key453 * @returns {ReflectionObject|null} Looked up object or `null` if none could be found454 * @private455 */456Namespace.prototype._lookupImpl = function lookup(path, flatPath) {457 if(Object.prototype.hasOwnProperty.call(this._lookupCache, flatPath)) {458 return this._lookupCache[flatPath];459 }460 461 // Test if the first part matches any nested object, and if so, traverse if path contains more462 var found = this.get(path[0]);463 var exact = null;464 if (found) {465 if (path.length === 1) {466 exact = found;467 } else if (found instanceof Namespace) {468 path = path.slice(1);469 exact = found._lookupImpl(path, path.join("."));470 }471 472 // Otherwise try each nested namespace473 } else {474 for (var i = 0; i < this.nestedArray.length; ++i)475 if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i]._lookupImpl(path, flatPath))) {476 exact = found;477 break;478 }479 }480 481 // Set this even when null, so that when we walk up the tree we can quickly bail on repeated checks back down.482 this._lookupCache[flatPath] = exact;483 return exact;484};485 486/**487 * Looks up the reflection object at the specified path, relative to this namespace.488 * @name NamespaceBase#lookup489 * @function490 * @param {string|string[]} path Path to look up491 * @param {boolean} [parentAlreadyChecked=false] Whether the parent has already been checked492 * @returns {ReflectionObject|null} Looked up object or `null` if none could be found493 * @variation 2494 */495// lookup(path: string, [parentAlreadyChecked: boolean])496 497/**498 * Looks up the {@link Type|type} at the specified path, relative to this namespace.499 * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.500 * @param {string|string[]} path Path to look up501 * @returns {Type} Looked up type502 * @throws {Error} If `path` does not point to a type503 */504Namespace.prototype.lookupType = function lookupType(path) {505 var found = this.lookup(path, [ Type ]);506 if (!found)507 throw Error("no such type: " + path);508 return found;509};510 511/**512 * Looks up the values of the {@link Enum|enum} at the specified path, relative to this namespace.513 * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.514 * @param {string|string[]} path Path to look up515 * @returns {Enum} Looked up enum516 * @throws {Error} If `path` does not point to an enum517 */518Namespace.prototype.lookupEnum = function lookupEnum(path) {519 var found = this.lookup(path, [ Enum ]);520 if (!found)521 throw Error("no such Enum '" + path + "' in " + this);522 return found;523};524 525/**526 * Looks up the {@link Type|type} or {@link Enum|enum} at the specified path, relative to this namespace.527 * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.528 * @param {string|string[]} path Path to look up529 * @returns {Type} Looked up type or enum530 * @throws {Error} If `path` does not point to a type or enum531 */532Namespace.prototype.lookupTypeOrEnum = function lookupTypeOrEnum(path) {533 var found = this.lookup(path, [ Type, Enum ]);534 if (!found)535 throw Error("no such Type or Enum '" + path + "' in " + this);536 return found;537};538 539/**540 * Looks up the {@link Service|service} at the specified path, relative to this namespace.541 * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.542 * @param {string|string[]} path Path to look up543 * @returns {Service} Looked up service544 * @throws {Error} If `path` does not point to a service545 */546Namespace.prototype.lookupService = function lookupService(path) {547 var found = this.lookup(path, [ Service ]);548 if (!found)549 throw Error("no such Service '" + path + "' in " + this);550 return found;551};552 553// Sets up cyclic dependencies (called in index-light)554Namespace._configure = function(Type_, Service_, Enum_) {555 Type = Type_;556 Service = Service_;557 Enum = Enum_;558};559 