mirror of
https://github.com/titanscouting/tra-analysis.git
synced 2025-02-07 03:25:46 +00:00
201 lines
4.9 KiB
JavaScript
201 lines
4.9 KiB
JavaScript
|
"use strict";
|
||
|
module.exports = ReflectionObject;
|
||
|
|
||
|
ReflectionObject.className = "ReflectionObject";
|
||
|
|
||
|
var util = require("./util");
|
||
|
|
||
|
var Root; // cyclic
|
||
|
|
||
|
/**
|
||
|
* Constructs a new reflection object instance.
|
||
|
* @classdesc Base class of all reflection objects.
|
||
|
* @constructor
|
||
|
* @param {string} name Object name
|
||
|
* @param {Object.<string,*>} [options] Declared options
|
||
|
* @abstract
|
||
|
*/
|
||
|
function ReflectionObject(name, options) {
|
||
|
|
||
|
if (!util.isString(name))
|
||
|
throw TypeError("name must be a string");
|
||
|
|
||
|
if (options && !util.isObject(options))
|
||
|
throw TypeError("options must be an object");
|
||
|
|
||
|
/**
|
||
|
* Options.
|
||
|
* @type {Object.<string,*>|undefined}
|
||
|
*/
|
||
|
this.options = options; // toJSON
|
||
|
|
||
|
/**
|
||
|
* Unique name within its namespace.
|
||
|
* @type {string}
|
||
|
*/
|
||
|
this.name = name;
|
||
|
|
||
|
/**
|
||
|
* Parent namespace.
|
||
|
* @type {Namespace|null}
|
||
|
*/
|
||
|
this.parent = null;
|
||
|
|
||
|
/**
|
||
|
* Whether already resolved or not.
|
||
|
* @type {boolean}
|
||
|
*/
|
||
|
this.resolved = false;
|
||
|
|
||
|
/**
|
||
|
* Comment text, if any.
|
||
|
* @type {string|null}
|
||
|
*/
|
||
|
this.comment = null;
|
||
|
|
||
|
/**
|
||
|
* Defining file name.
|
||
|
* @type {string|null}
|
||
|
*/
|
||
|
this.filename = null;
|
||
|
}
|
||
|
|
||
|
Object.defineProperties(ReflectionObject.prototype, {
|
||
|
|
||
|
/**
|
||
|
* Reference to the root namespace.
|
||
|
* @name ReflectionObject#root
|
||
|
* @type {Root}
|
||
|
* @readonly
|
||
|
*/
|
||
|
root: {
|
||
|
get: function() {
|
||
|
var ptr = this;
|
||
|
while (ptr.parent !== null)
|
||
|
ptr = ptr.parent;
|
||
|
return ptr;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Full name including leading dot.
|
||
|
* @name ReflectionObject#fullName
|
||
|
* @type {string}
|
||
|
* @readonly
|
||
|
*/
|
||
|
fullName: {
|
||
|
get: function() {
|
||
|
var path = [ this.name ],
|
||
|
ptr = this.parent;
|
||
|
while (ptr) {
|
||
|
path.unshift(ptr.name);
|
||
|
ptr = ptr.parent;
|
||
|
}
|
||
|
return path.join(".");
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Converts this reflection object to its descriptor representation.
|
||
|
* @returns {Object.<string,*>} Descriptor
|
||
|
* @abstract
|
||
|
*/
|
||
|
ReflectionObject.prototype.toJSON = /* istanbul ignore next */ function toJSON() {
|
||
|
throw Error(); // not implemented, shouldn't happen
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Called when this object is added to a parent.
|
||
|
* @param {ReflectionObject} parent Parent added to
|
||
|
* @returns {undefined}
|
||
|
*/
|
||
|
ReflectionObject.prototype.onAdd = function onAdd(parent) {
|
||
|
if (this.parent && this.parent !== parent)
|
||
|
this.parent.remove(this);
|
||
|
this.parent = parent;
|
||
|
this.resolved = false;
|
||
|
var root = parent.root;
|
||
|
if (root instanceof Root)
|
||
|
root._handleAdd(this);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Called when this object is removed from a parent.
|
||
|
* @param {ReflectionObject} parent Parent removed from
|
||
|
* @returns {undefined}
|
||
|
*/
|
||
|
ReflectionObject.prototype.onRemove = function onRemove(parent) {
|
||
|
var root = parent.root;
|
||
|
if (root instanceof Root)
|
||
|
root._handleRemove(this);
|
||
|
this.parent = null;
|
||
|
this.resolved = false;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Resolves this objects type references.
|
||
|
* @returns {ReflectionObject} `this`
|
||
|
*/
|
||
|
ReflectionObject.prototype.resolve = function resolve() {
|
||
|
if (this.resolved)
|
||
|
return this;
|
||
|
if (this.root instanceof Root)
|
||
|
this.resolved = true; // only if part of a root
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Gets an option value.
|
||
|
* @param {string} name Option name
|
||
|
* @returns {*} Option value or `undefined` if not set
|
||
|
*/
|
||
|
ReflectionObject.prototype.getOption = function getOption(name) {
|
||
|
if (this.options)
|
||
|
return this.options[name];
|
||
|
return undefined;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Sets an option.
|
||
|
* @param {string} name Option name
|
||
|
* @param {*} value Option value
|
||
|
* @param {boolean} [ifNotSet] Sets the option only if it isn't currently set
|
||
|
* @returns {ReflectionObject} `this`
|
||
|
*/
|
||
|
ReflectionObject.prototype.setOption = function setOption(name, value, ifNotSet) {
|
||
|
if (!ifNotSet || !this.options || this.options[name] === undefined)
|
||
|
(this.options || (this.options = {}))[name] = value;
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Sets multiple options.
|
||
|
* @param {Object.<string,*>} options Options to set
|
||
|
* @param {boolean} [ifNotSet] Sets an option only if it isn't currently set
|
||
|
* @returns {ReflectionObject} `this`
|
||
|
*/
|
||
|
ReflectionObject.prototype.setOptions = function setOptions(options, ifNotSet) {
|
||
|
if (options)
|
||
|
for (var keys = Object.keys(options), i = 0; i < keys.length; ++i)
|
||
|
this.setOption(keys[i], options[keys[i]], ifNotSet);
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Converts this instance to its string representation.
|
||
|
* @returns {string} Class name[, space, full name]
|
||
|
*/
|
||
|
ReflectionObject.prototype.toString = function toString() {
|
||
|
var className = this.constructor.className,
|
||
|
fullName = this.fullName;
|
||
|
if (fullName.length)
|
||
|
return className + " " + fullName;
|
||
|
return className;
|
||
|
};
|
||
|
|
||
|
// Sets up cyclic dependencies (called in index-light)
|
||
|
ReflectionObject._configure = function(Root_) {
|
||
|
Root = Root_;
|
||
|
};
|