2 module.exports = OneOf;
4 // extends ReflectionObject
5 var ReflectionObject = require("./object");
6 ((OneOf.prototype = Object.create(ReflectionObject.prototype)).constructor = OneOf).className = "OneOf";
8 var Field = require("./field"),
9 util = require("./util");
12 * Constructs a new oneof instance.
13 * @classdesc Reflected oneof.
14 * @extends ReflectionObject
16 * @param {string} name Oneof name
17 * @param {string[]|Object.<string,*>} [fieldNames] Field names
18 * @param {Object.<string,*>} [options] Declared options
19 * @param {string} [comment] Comment associated with this field
21 function OneOf(name, fieldNames, options, comment) {
22 if (!Array.isArray(fieldNames)) {
24 fieldNames = undefined;
26 ReflectionObject.call(this, name, options);
28 /* istanbul ignore if */
29 if (!(fieldNames === undefined || Array.isArray(fieldNames)))
30 throw TypeError("fieldNames must be an Array");
33 * Field names that belong to this oneof.
36 this.oneof = fieldNames || []; // toJSON, marker
39 * Fields that belong to this oneof as an array for iteration.
43 this.fieldsArray = []; // declared readonly for conformance, possibly not yet added to parent
46 * Comment for this field.
49 this.comment = comment;
55 * @property {Array.<string>} oneof Oneof field names
56 * @property {Object.<string,*>} [options] Oneof options
60 * Constructs a oneof from a oneof descriptor.
61 * @param {string} name Oneof name
62 * @param {IOneOf} json Oneof descriptor
63 * @returns {OneOf} Created oneof
64 * @throws {TypeError} If arguments are invalid
66 OneOf.fromJSON = function fromJSON(name, json) {
67 return new OneOf(name, json.oneof, json.options, json.comment);
71 * Converts this oneof to a oneof descriptor.
72 * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
73 * @returns {IOneOf} Oneof descriptor
75 OneOf.prototype.toJSON = function toJSON(toJSONOptions) {
76 var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
77 return util.toObject([
78 "options" , this.options,
80 "comment" , keepComments ? this.comment : undefined
85 * Adds the fields of the specified oneof to the parent if not already done so.
86 * @param {OneOf} oneof The oneof
87 * @returns {undefined}
91 function addFieldsToParent(oneof) {
93 for (var i = 0; i < oneof.fieldsArray.length; ++i)
94 if (!oneof.fieldsArray[i].parent)
95 oneof.parent.add(oneof.fieldsArray[i]);
99 * Adds a field to this oneof and removes it from its current parent, if any.
100 * @param {Field} field Field to add
101 * @returns {OneOf} `this`
103 OneOf.prototype.add = function add(field) {
105 /* istanbul ignore if */
106 if (!(field instanceof Field))
107 throw TypeError("field must be a Field");
109 if (field.parent && field.parent !== this.parent)
110 field.parent.remove(field);
111 this.oneof.push(field.name);
112 this.fieldsArray.push(field);
113 field.partOf = this; // field.parent remains null
114 addFieldsToParent(this);
119 * Removes a field from this oneof and puts it back to the oneof's parent.
120 * @param {Field} field Field to remove
121 * @returns {OneOf} `this`
123 OneOf.prototype.remove = function remove(field) {
125 /* istanbul ignore if */
126 if (!(field instanceof Field))
127 throw TypeError("field must be a Field");
129 var index = this.fieldsArray.indexOf(field);
131 /* istanbul ignore if */
133 throw Error(field + " is not a member of " + this);
135 this.fieldsArray.splice(index, 1);
136 index = this.oneof.indexOf(field.name);
138 /* istanbul ignore else */
139 if (index > -1) // theoretical
140 this.oneof.splice(index, 1);
149 OneOf.prototype.onAdd = function onAdd(parent) {
150 ReflectionObject.prototype.onAdd.call(this, parent);
152 // Collect present fields
153 for (var i = 0; i < this.oneof.length; ++i) {
154 var field = parent.get(this.oneof[i]);
155 if (field && !field.partOf) {
157 self.fieldsArray.push(field);
160 // Add not yet present fields
161 addFieldsToParent(this);
167 OneOf.prototype.onRemove = function onRemove(parent) {
168 for (var i = 0, field; i < this.fieldsArray.length; ++i)
169 if ((field = this.fieldsArray[i]).parent)
170 field.parent.remove(field);
171 ReflectionObject.prototype.onRemove.call(this, parent);
175 * Decorator function as returned by {@link OneOf.d} (TypeScript).
176 * @typedef OneOfDecorator
178 * @param {Object} prototype Target prototype
179 * @param {string} oneofName OneOf name
180 * @returns {undefined}
184 * OneOf decorator (TypeScript).
186 * @param {...string} fieldNames Field names
187 * @returns {OneOfDecorator} Decorator function
188 * @template T extends string
190 OneOf.d = function decorateOneOf() {
191 var fieldNames = new Array(arguments.length),
193 while (index < arguments.length)
194 fieldNames[index] = arguments[index++];
195 return function oneOfDecorator(prototype, oneofName) {
196 util.decorateType(prototype.constructor)
197 .add(new OneOf(oneofName, fieldNames));
198 Object.defineProperty(prototype, oneofName, {
199 get: util.oneOfGetter(fieldNames),
200 set: util.oneOfSetter(fieldNames)