Buckets:
| ; | |
| module.exports = Root; | |
| // extends Namespace | |
| var Namespace = require("./namespace"); | |
| ((Root.prototype = Object.create(Namespace.prototype)).constructor = Root).className = "Root"; | |
| var Field = require("./field"), | |
| Enum = require("./enum"), | |
| OneOf = require("./oneof"), | |
| util = require("./util"); | |
| var Type, // cyclic | |
| parse, // might be excluded | |
| common; // " | |
| /** | |
| * Constructs a new root namespace instance. | |
| * @classdesc Root namespace wrapping all types, enums, services, sub-namespaces etc. that belong together. | |
| * @extends NamespaceBase | |
| * @constructor | |
| * @param {Object.<string,*>} [options] Top level options | |
| */ | |
| function Root(options) { | |
| Namespace.call(this, "", options); | |
| /** | |
| * Deferred extension fields. | |
| * @type {Field[]} | |
| */ | |
| this.deferred = []; | |
| /** | |
| * Resolved file names of loaded files. | |
| * @type {string[]} | |
| */ | |
| this.files = []; | |
| /** | |
| * Edition, defaults to proto2 if unspecified. | |
| * @type {string} | |
| * @private | |
| */ | |
| this._edition = "proto2"; | |
| /** | |
| * Global lookup cache of fully qualified names. | |
| * @type {Object.<string,ReflectionObject>} | |
| * @private | |
| */ | |
| this._fullyQualifiedObjects = {}; | |
| } | |
| /** | |
| * Loads a namespace descriptor into a root namespace. | |
| * @param {INamespace} json Namespace descriptor | |
| * @param {Root} [root] Root namespace, defaults to create a new one if omitted | |
| * @returns {Root} Root namespace | |
| */ | |
| Root.fromJSON = function fromJSON(json, root) { | |
| if (!root) | |
| root = new Root(); | |
| if (json.options) | |
| root.setOptions(json.options); | |
| return root.addJSON(json.nested).resolveAll(); | |
| }; | |
| /** | |
| * Resolves the path of an imported file, relative to the importing origin. | |
| * This method exists so you can override it with your own logic in case your imports are scattered over multiple directories. | |
| * @function | |
| * @param {string} origin The file name of the importing file | |
| * @param {string} target The file name being imported | |
| * @returns {string|null} Resolved path to `target` or `null` to skip the file | |
| */ | |
| Root.prototype.resolvePath = util.path.resolve; | |
| /** | |
| * Fetch content from file path or url | |
| * This method exists so you can override it with your own logic. | |
| * @function | |
| * @param {string} path File path or url | |
| * @param {FetchCallback} callback Callback function | |
| * @returns {undefined} | |
| */ | |
| Root.prototype.fetch = util.fetch; | |
| // A symbol-like function to safely signal synchronous loading | |
| /* istanbul ignore next */ | |
| function SYNC() {} // eslint-disable-line no-empty-function | |
| /** | |
| * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback. | |
| * @param {string|string[]} filename Names of one or multiple files to load | |
| * @param {IParseOptions} options Parse options | |
| * @param {LoadCallback} callback Callback function | |
| * @returns {undefined} | |
| */ | |
| Root.prototype.load = function load(filename, options, callback) { | |
| if (typeof options === "function") { | |
| callback = options; | |
| options = undefined; | |
| } | |
| var self = this; | |
| if (!callback) { | |
| return util.asPromise(load, self, filename, options); | |
| } | |
| var sync = callback === SYNC; // undocumented | |
| // Finishes loading by calling the callback (exactly once) | |
| function finish(err, root) { | |
| /* istanbul ignore if */ | |
| if (!callback) { | |
| return; | |
| } | |
| if (sync) { | |
| throw err; | |
| } | |
| if (root) { | |
| root.resolveAll(); | |
| } | |
| var cb = callback; | |
| callback = null; | |
| cb(err, root); | |
| } | |
| // Bundled definition existence checking | |
| function getBundledFileName(filename) { | |
| var idx = filename.lastIndexOf("google/protobuf/"); | |
| if (idx > -1) { | |
| var altname = filename.substring(idx); | |
| if (altname in common) return altname; | |
| } | |
| return null; | |
| } | |
| // Processes a single file | |
| function process(filename, source) { | |
| try { | |
| if (util.isString(source) && source.charAt(0) === "{") | |
| source = JSON.parse(source); | |
| if (!util.isString(source)) | |
| self.setOptions(source.options).addJSON(source.nested); | |
| else { | |
| parse.filename = filename; | |
| var parsed = parse(source, self, options), | |
| resolved, | |
| i = 0; | |
| if (parsed.imports) | |
| for (; i < parsed.imports.length; ++i) | |
| if (resolved = getBundledFileName(parsed.imports[i]) || self.resolvePath(filename, parsed.imports[i])) | |
| fetch(resolved); | |
| if (parsed.weakImports) | |
| for (i = 0; i < parsed.weakImports.length; ++i) | |
| if (resolved = getBundledFileName(parsed.weakImports[i]) || self.resolvePath(filename, parsed.weakImports[i])) | |
| fetch(resolved, true); | |
| } | |
| } catch (err) { | |
| finish(err); | |
| } | |
| if (!sync && !queued) { | |
| finish(null, self); // only once anyway | |
| } | |
| } | |
| // Fetches a single file | |
| function fetch(filename, weak) { | |
| filename = getBundledFileName(filename) || filename; | |
| // Skip if already loaded / attempted | |
| if (self.files.indexOf(filename) > -1) { | |
| return; | |
| } | |
| self.files.push(filename); | |
| // Shortcut bundled definitions | |
| if (filename in common) { | |
| if (sync) { | |
| process(filename, common[filename]); | |
| } else { | |
| ++queued; | |
| setTimeout(function() { | |
| --queued; | |
| process(filename, common[filename]); | |
| }); | |
| } | |
| return; | |
| } | |
| // Otherwise fetch from disk or network | |
| if (sync) { | |
| var source; | |
| try { | |
| source = util.fs.readFileSync(filename).toString("utf8"); | |
| } catch (err) { | |
| if (!weak) | |
| finish(err); | |
| return; | |
| } | |
| process(filename, source); | |
| } else { | |
| ++queued; | |
| self.fetch(filename, function(err, source) { | |
| --queued; | |
| /* istanbul ignore if */ | |
| if (!callback) { | |
| return; // terminated meanwhile | |
| } | |
| if (err) { | |
| /* istanbul ignore else */ | |
| if (!weak) | |
| finish(err); | |
| else if (!queued) // can't be covered reliably | |
| finish(null, self); | |
| return; | |
| } | |
| process(filename, source); | |
| }); | |
| } | |
| } | |
| var queued = 0; | |
| // Assembling the root namespace doesn't require working type | |
| // references anymore, so we can load everything in parallel | |
| if (util.isString(filename)) { | |
| filename = [ filename ]; | |
| } | |
| for (var i = 0, resolved; i < filename.length; ++i) | |
| if (resolved = self.resolvePath("", filename[i])) | |
| fetch(resolved); | |
| if (sync) { | |
| self.resolveAll(); | |
| return self; | |
| } | |
| if (!queued) { | |
| finish(null, self); | |
| } | |
| return self; | |
| }; | |
| // function load(filename:string, options:IParseOptions, callback:LoadCallback):undefined | |
| /** | |
| * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback. | |
| * @function Root#load | |
| * @param {string|string[]} filename Names of one or multiple files to load | |
| * @param {LoadCallback} callback Callback function | |
| * @returns {undefined} | |
| * @variation 2 | |
| */ | |
| // function load(filename:string, callback:LoadCallback):undefined | |
| /** | |
| * Loads one or multiple .proto or preprocessed .json files into this root namespace and returns a promise. | |
| * @function Root#load | |
| * @param {string|string[]} filename Names of one or multiple files to load | |
| * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted. | |
| * @returns {Promise<Root>} Promise | |
| * @variation 3 | |
| */ | |
| // function load(filename:string, [options:IParseOptions]):Promise<Root> | |
| /** | |
| * Synchronously loads one or multiple .proto or preprocessed .json files into this root namespace (node only). | |
| * @function Root#loadSync | |
| * @param {string|string[]} filename Names of one or multiple files to load | |
| * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted. | |
| * @returns {Root} Root namespace | |
| * @throws {Error} If synchronous fetching is not supported (i.e. in browsers) or if a file's syntax is invalid | |
| */ | |
| Root.prototype.loadSync = function loadSync(filename, options) { | |
| if (!util.isNode) | |
| throw Error("not supported"); | |
| return this.load(filename, options, SYNC); | |
| }; | |
| /** | |
| * @override | |
| */ | |
| Root.prototype.resolveAll = function resolveAll() { | |
| if (!this._needsRecursiveResolve) return this; | |
| if (this.deferred.length) | |
| throw Error("unresolvable extensions: " + this.deferred.map(function(field) { | |
| return "'extend " + field.extend + "' in " + field.parent.fullName; | |
| }).join(", ")); | |
| return Namespace.prototype.resolveAll.call(this); | |
| }; | |
| // only uppercased (and thus conflict-free) children are exposed, see below | |
| var exposeRe = /^[A-Z]/; | |
| /** | |
| * Handles a deferred declaring extension field by creating a sister field to represent it within its extended type. | |
| * @param {Root} root Root instance | |
| * @param {Field} field Declaring extension field witin the declaring type | |
| * @returns {boolean} `true` if successfully added to the extended type, `false` otherwise | |
| * @inner | |
| * @ignore | |
| */ | |
| function tryHandleExtension(root, field) { | |
| var extendedType = field.parent.lookup(field.extend); | |
| if (extendedType) { | |
| var sisterField = new Field(field.fullName, field.id, field.type, field.rule, undefined, field.options); | |
| //do not allow to extend same field twice to prevent the error | |
| if (extendedType.get(sisterField.name)) { | |
| return true; | |
| } | |
| sisterField.declaringField = field; | |
| field.extensionField = sisterField; | |
| extendedType.add(sisterField); | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Called when any object is added to this root or its sub-namespaces. | |
| * @param {ReflectionObject} object Object added | |
| * @returns {undefined} | |
| * @private | |
| */ | |
| Root.prototype._handleAdd = function _handleAdd(object) { | |
| if (object instanceof Field) { | |
| if (/* an extension field (implies not part of a oneof) */ object.extend !== undefined && /* not already handled */ !object.extensionField) | |
| if (!tryHandleExtension(this, object)) | |
| this.deferred.push(object); | |
| } else if (object instanceof Enum) { | |
| if (exposeRe.test(object.name)) | |
| object.parent[object.name] = object.values; // expose enum values as property of its parent | |
| } else if (!(object instanceof OneOf)) /* everything else is a namespace */ { | |
| if (object instanceof Type) // Try to handle any deferred extensions | |
| for (var i = 0; i < this.deferred.length;) | |
| if (tryHandleExtension(this, this.deferred[i])) | |
| this.deferred.splice(i, 1); | |
| else | |
| ++i; | |
| for (var j = 0; j < /* initializes */ object.nestedArray.length; ++j) // recurse into the namespace | |
| this._handleAdd(object._nestedArray[j]); | |
| if (exposeRe.test(object.name)) | |
| object.parent[object.name] = object; // expose namespace as property of its parent | |
| } | |
| if (object instanceof Type || object instanceof Enum || object instanceof Field) { | |
| // Only store types and enums for quick lookup during resolve. | |
| this._fullyQualifiedObjects[object.fullName] = object; | |
| } | |
| // The above also adds uppercased (and thus conflict-free) nested types, services and enums as | |
| // properties of namespaces just like static code does. This allows using a .d.ts generated for | |
| // a static module with reflection-based solutions where the condition is met. | |
| }; | |
| /** | |
| * Called when any object is removed from this root or its sub-namespaces. | |
| * @param {ReflectionObject} object Object removed | |
| * @returns {undefined} | |
| * @private | |
| */ | |
| Root.prototype._handleRemove = function _handleRemove(object) { | |
| if (object instanceof Field) { | |
| if (/* an extension field */ object.extend !== undefined) { | |
| if (/* already handled */ object.extensionField) { // remove its sister field | |
| object.extensionField.parent.remove(object.extensionField); | |
| object.extensionField = null; | |
| } else { // cancel the extension | |
| var index = this.deferred.indexOf(object); | |
| /* istanbul ignore else */ | |
| if (index > -1) | |
| this.deferred.splice(index, 1); | |
| } | |
| } | |
| } else if (object instanceof Enum) { | |
| if (exposeRe.test(object.name)) | |
| delete object.parent[object.name]; // unexpose enum values | |
| } else if (object instanceof Namespace) { | |
| for (var i = 0; i < /* initializes */ object.nestedArray.length; ++i) // recurse into the namespace | |
| this._handleRemove(object._nestedArray[i]); | |
| if (exposeRe.test(object.name)) | |
| delete object.parent[object.name]; // unexpose namespaces | |
| } | |
| delete this._fullyQualifiedObjects[object.fullName]; | |
| }; | |
| // Sets up cyclic dependencies (called in index-light) | |
| Root._configure = function(Type_, parse_, common_) { | |
| Type = Type_; | |
| parse = parse_; | |
| common = common_; | |
| }; | |
Xet Storage Details
- Size:
- 13.7 kB
- Xet hash:
- 2d8af3c381bcf8229dc69e4a1dbef9dce4e801ea23f7cfbbc15733e1ec816f31
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.