mirror of
https://github.com/titanscouting/tra-analysis.git
synced 2025-05-02 13:37:22 +00:00
204 lines
5.6 KiB
JavaScript
204 lines
5.6 KiB
JavaScript
"use strict";
|
|
module.exports = OneOf;
|
|
|
|
// extends ReflectionObject
|
|
var ReflectionObject = require("./object");
|
|
((OneOf.prototype = Object.create(ReflectionObject.prototype)).constructor = OneOf).className = "OneOf";
|
|
|
|
var Field = require("./field"),
|
|
util = require("./util");
|
|
|
|
/**
|
|
* Constructs a new oneof instance.
|
|
* @classdesc Reflected oneof.
|
|
* @extends ReflectionObject
|
|
* @constructor
|
|
* @param {string} name Oneof name
|
|
* @param {string[]|Object.<string,*>} [fieldNames] Field names
|
|
* @param {Object.<string,*>} [options] Declared options
|
|
* @param {string} [comment] Comment associated with this field
|
|
*/
|
|
function OneOf(name, fieldNames, options, comment) {
|
|
if (!Array.isArray(fieldNames)) {
|
|
options = fieldNames;
|
|
fieldNames = undefined;
|
|
}
|
|
ReflectionObject.call(this, name, options);
|
|
|
|
/* istanbul ignore if */
|
|
if (!(fieldNames === undefined || Array.isArray(fieldNames)))
|
|
throw TypeError("fieldNames must be an Array");
|
|
|
|
/**
|
|
* Field names that belong to this oneof.
|
|
* @type {string[]}
|
|
*/
|
|
this.oneof = fieldNames || []; // toJSON, marker
|
|
|
|
/**
|
|
* Fields that belong to this oneof as an array for iteration.
|
|
* @type {Field[]}
|
|
* @readonly
|
|
*/
|
|
this.fieldsArray = []; // declared readonly for conformance, possibly not yet added to parent
|
|
|
|
/**
|
|
* Comment for this field.
|
|
* @type {string|null}
|
|
*/
|
|
this.comment = comment;
|
|
}
|
|
|
|
/**
|
|
* Oneof descriptor.
|
|
* @interface IOneOf
|
|
* @property {Array.<string>} oneof Oneof field names
|
|
* @property {Object.<string,*>} [options] Oneof options
|
|
*/
|
|
|
|
/**
|
|
* Constructs a oneof from a oneof descriptor.
|
|
* @param {string} name Oneof name
|
|
* @param {IOneOf} json Oneof descriptor
|
|
* @returns {OneOf} Created oneof
|
|
* @throws {TypeError} If arguments are invalid
|
|
*/
|
|
OneOf.fromJSON = function fromJSON(name, json) {
|
|
return new OneOf(name, json.oneof, json.options, json.comment);
|
|
};
|
|
|
|
/**
|
|
* Converts this oneof to a oneof descriptor.
|
|
* @param {IToJSONOptions} [toJSONOptions] JSON conversion options
|
|
* @returns {IOneOf} Oneof descriptor
|
|
*/
|
|
OneOf.prototype.toJSON = function toJSON(toJSONOptions) {
|
|
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
|
|
return util.toObject([
|
|
"options" , this.options,
|
|
"oneof" , this.oneof,
|
|
"comment" , keepComments ? this.comment : undefined
|
|
]);
|
|
};
|
|
|
|
/**
|
|
* Adds the fields of the specified oneof to the parent if not already done so.
|
|
* @param {OneOf} oneof The oneof
|
|
* @returns {undefined}
|
|
* @inner
|
|
* @ignore
|
|
*/
|
|
function addFieldsToParent(oneof) {
|
|
if (oneof.parent)
|
|
for (var i = 0; i < oneof.fieldsArray.length; ++i)
|
|
if (!oneof.fieldsArray[i].parent)
|
|
oneof.parent.add(oneof.fieldsArray[i]);
|
|
}
|
|
|
|
/**
|
|
* Adds a field to this oneof and removes it from its current parent, if any.
|
|
* @param {Field} field Field to add
|
|
* @returns {OneOf} `this`
|
|
*/
|
|
OneOf.prototype.add = function add(field) {
|
|
|
|
/* istanbul ignore if */
|
|
if (!(field instanceof Field))
|
|
throw TypeError("field must be a Field");
|
|
|
|
if (field.parent && field.parent !== this.parent)
|
|
field.parent.remove(field);
|
|
this.oneof.push(field.name);
|
|
this.fieldsArray.push(field);
|
|
field.partOf = this; // field.parent remains null
|
|
addFieldsToParent(this);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Removes a field from this oneof and puts it back to the oneof's parent.
|
|
* @param {Field} field Field to remove
|
|
* @returns {OneOf} `this`
|
|
*/
|
|
OneOf.prototype.remove = function remove(field) {
|
|
|
|
/* istanbul ignore if */
|
|
if (!(field instanceof Field))
|
|
throw TypeError("field must be a Field");
|
|
|
|
var index = this.fieldsArray.indexOf(field);
|
|
|
|
/* istanbul ignore if */
|
|
if (index < 0)
|
|
throw Error(field + " is not a member of " + this);
|
|
|
|
this.fieldsArray.splice(index, 1);
|
|
index = this.oneof.indexOf(field.name);
|
|
|
|
/* istanbul ignore else */
|
|
if (index > -1) // theoretical
|
|
this.oneof.splice(index, 1);
|
|
|
|
field.partOf = null;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
OneOf.prototype.onAdd = function onAdd(parent) {
|
|
ReflectionObject.prototype.onAdd.call(this, parent);
|
|
var self = this;
|
|
// Collect present fields
|
|
for (var i = 0; i < this.oneof.length; ++i) {
|
|
var field = parent.get(this.oneof[i]);
|
|
if (field && !field.partOf) {
|
|
field.partOf = self;
|
|
self.fieldsArray.push(field);
|
|
}
|
|
}
|
|
// Add not yet present fields
|
|
addFieldsToParent(this);
|
|
};
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
OneOf.prototype.onRemove = function onRemove(parent) {
|
|
for (var i = 0, field; i < this.fieldsArray.length; ++i)
|
|
if ((field = this.fieldsArray[i]).parent)
|
|
field.parent.remove(field);
|
|
ReflectionObject.prototype.onRemove.call(this, parent);
|
|
};
|
|
|
|
/**
|
|
* Decorator function as returned by {@link OneOf.d} (TypeScript).
|
|
* @typedef OneOfDecorator
|
|
* @type {function}
|
|
* @param {Object} prototype Target prototype
|
|
* @param {string} oneofName OneOf name
|
|
* @returns {undefined}
|
|
*/
|
|
|
|
/**
|
|
* OneOf decorator (TypeScript).
|
|
* @function
|
|
* @param {...string} fieldNames Field names
|
|
* @returns {OneOfDecorator} Decorator function
|
|
* @template T extends string
|
|
*/
|
|
OneOf.d = function decorateOneOf() {
|
|
var fieldNames = new Array(arguments.length),
|
|
index = 0;
|
|
while (index < arguments.length)
|
|
fieldNames[index] = arguments[index++];
|
|
return function oneOfDecorator(prototype, oneofName) {
|
|
util.decorateType(prototype.constructor)
|
|
.add(new OneOf(oneofName, fieldNames));
|
|
Object.defineProperty(prototype, oneofName, {
|
|
get: util.oneOfGetter(fieldNames),
|
|
set: util.oneOfSetter(fieldNames)
|
|
});
|
|
};
|
|
};
|