Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / protobufjs / src / oneof.js
1 "use strict";
2 module.exports = OneOf;
3
4 // extends ReflectionObject
5 var ReflectionObject = require("./object");
6 ((OneOf.prototype = Object.create(ReflectionObject.prototype)).constructor = OneOf).className = "OneOf";
7
8 var Field = require("./field"),
9     util  = require("./util");
10
11 /**
12  * Constructs a new oneof instance.
13  * @classdesc Reflected oneof.
14  * @extends ReflectionObject
15  * @constructor
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
20  */
21 function OneOf(name, fieldNames, options, comment) {
22     if (!Array.isArray(fieldNames)) {
23         options = fieldNames;
24         fieldNames = undefined;
25     }
26     ReflectionObject.call(this, name, options);
27
28     /* istanbul ignore if */
29     if (!(fieldNames === undefined || Array.isArray(fieldNames)))
30         throw TypeError("fieldNames must be an Array");
31
32     /**
33      * Field names that belong to this oneof.
34      * @type {string[]}
35      */
36     this.oneof = fieldNames || []; // toJSON, marker
37
38     /**
39      * Fields that belong to this oneof as an array for iteration.
40      * @type {Field[]}
41      * @readonly
42      */
43     this.fieldsArray = []; // declared readonly for conformance, possibly not yet added to parent
44
45     /**
46      * Comment for this field.
47      * @type {string|null}
48      */
49     this.comment = comment;
50 }
51
52 /**
53  * Oneof descriptor.
54  * @interface IOneOf
55  * @property {Array.<string>} oneof Oneof field names
56  * @property {Object.<string,*>} [options] Oneof options
57  */
58
59 /**
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
65  */
66 OneOf.fromJSON = function fromJSON(name, json) {
67     return new OneOf(name, json.oneof, json.options, json.comment);
68 };
69
70 /**
71  * Converts this oneof to a oneof descriptor.
72  * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
73  * @returns {IOneOf} Oneof descriptor
74  */
75 OneOf.prototype.toJSON = function toJSON(toJSONOptions) {
76     var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
77     return util.toObject([
78         "options" , this.options,
79         "oneof"   , this.oneof,
80         "comment" , keepComments ? this.comment : undefined
81     ]);
82 };
83
84 /**
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}
88  * @inner
89  * @ignore
90  */
91 function addFieldsToParent(oneof) {
92     if (oneof.parent)
93         for (var i = 0; i < oneof.fieldsArray.length; ++i)
94             if (!oneof.fieldsArray[i].parent)
95                 oneof.parent.add(oneof.fieldsArray[i]);
96 }
97
98 /**
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`
102  */
103 OneOf.prototype.add = function add(field) {
104
105     /* istanbul ignore if */
106     if (!(field instanceof Field))
107         throw TypeError("field must be a Field");
108
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);
115     return this;
116 };
117
118 /**
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`
122  */
123 OneOf.prototype.remove = function remove(field) {
124
125     /* istanbul ignore if */
126     if (!(field instanceof Field))
127         throw TypeError("field must be a Field");
128
129     var index = this.fieldsArray.indexOf(field);
130
131     /* istanbul ignore if */
132     if (index < 0)
133         throw Error(field + " is not a member of " + this);
134
135     this.fieldsArray.splice(index, 1);
136     index = this.oneof.indexOf(field.name);
137
138     /* istanbul ignore else */
139     if (index > -1) // theoretical
140         this.oneof.splice(index, 1);
141
142     field.partOf = null;
143     return this;
144 };
145
146 /**
147  * @override
148  */
149 OneOf.prototype.onAdd = function onAdd(parent) {
150     ReflectionObject.prototype.onAdd.call(this, parent);
151     var self = this;
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) {
156             field.partOf = self;
157             self.fieldsArray.push(field);
158         }
159     }
160     // Add not yet present fields
161     addFieldsToParent(this);
162 };
163
164 /**
165  * @override
166  */
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);
172 };
173
174 /**
175  * Decorator function as returned by {@link OneOf.d} (TypeScript).
176  * @typedef OneOfDecorator
177  * @type {function}
178  * @param {Object} prototype Target prototype
179  * @param {string} oneofName OneOf name
180  * @returns {undefined}
181  */
182
183 /**
184  * OneOf decorator (TypeScript).
185  * @function
186  * @param {...string} fieldNames Field names
187  * @returns {OneOfDecorator} Decorator function
188  * @template T extends string
189  */
190 OneOf.d = function decorateOneOf() {
191     var fieldNames = new Array(arguments.length),
192         index = 0;
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)
201         });
202     };
203 };