4 // extends ReflectionObject
5 var ReflectionObject = require("./object");
6 ((Enum.prototype = Object.create(ReflectionObject.prototype)).constructor = Enum).className = "Enum";
8 var Namespace = require("./namespace"),
9 util = require("./util");
12 * Constructs a new enum instance.
13 * @classdesc Reflected enum.
14 * @extends ReflectionObject
16 * @param {string} name Unique name within its namespace
17 * @param {Object.<string,number>} [values] Enum values as an object, by name
18 * @param {Object.<string,*>} [options] Declared options
19 * @param {string} [comment] The comment for this enum
20 * @param {Object.<string,string>} [comments] The value comments for this enum
22 function Enum(name, values, options, comment, comments) {
23 ReflectionObject.call(this, name, options);
25 if (values && typeof values !== "object")
26 throw TypeError("values must be an object");
30 * @type {Object.<number,string>}
35 * Enum values by name.
36 * @type {Object.<string,number>}
38 this.values = Object.create(this.valuesById); // toJSON, marker
44 this.comment = comment;
47 * Value comment texts, if any.
48 * @type {Object.<string,string>}
50 this.comments = comments || {};
53 * Reserved ranges, if any.
54 * @type {Array.<number[]|string>}
56 this.reserved = undefined; // toJSON
58 // Note that values inherit valuesById on their prototype which makes them a TypeScript-
59 // compatible enum. This is used by pbts to write actual enum definitions that work for
60 // static and reflection code alike instead of emitting generic object definitions.
63 for (var keys = Object.keys(values), i = 0; i < keys.length; ++i)
64 if (typeof values[keys[i]] === "number") // use forward entries only
65 this.valuesById[ this.values[keys[i]] = values[keys[i]] ] = keys[i];
71 * @property {Object.<string,number>} values Enum values
72 * @property {Object.<string,*>} [options] Enum options
76 * Constructs an enum from an enum descriptor.
77 * @param {string} name Enum name
78 * @param {IEnum} json Enum descriptor
79 * @returns {Enum} Created enum
80 * @throws {TypeError} If arguments are invalid
82 Enum.fromJSON = function fromJSON(name, json) {
83 var enm = new Enum(name, json.values, json.options, json.comment, json.comments);
84 enm.reserved = json.reserved;
89 * Converts this enum to an enum descriptor.
90 * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
91 * @returns {IEnum} Enum descriptor
93 Enum.prototype.toJSON = function toJSON(toJSONOptions) {
94 var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
95 return util.toObject([
96 "options" , this.options,
97 "values" , this.values,
98 "reserved" , this.reserved && this.reserved.length ? this.reserved : undefined,
99 "comment" , keepComments ? this.comment : undefined,
100 "comments" , keepComments ? this.comments : undefined
105 * Adds a value to this enum.
106 * @param {string} name Value name
107 * @param {number} id Value id
108 * @param {string} [comment] Comment, if any
109 * @returns {Enum} `this`
110 * @throws {TypeError} If arguments are invalid
111 * @throws {Error} If there is already a value with this name or id
113 Enum.prototype.add = function add(name, id, comment) {
114 // utilized by the parser but not by .fromJSON
116 if (!util.isString(name))
117 throw TypeError("name must be a string");
119 if (!util.isInteger(id))
120 throw TypeError("id must be an integer");
122 if (this.values[name] !== undefined)
123 throw Error("duplicate name '" + name + "' in " + this);
125 if (this.isReservedId(id))
126 throw Error("id " + id + " is reserved in " + this);
128 if (this.isReservedName(name))
129 throw Error("name '" + name + "' is reserved in " + this);
131 if (this.valuesById[id] !== undefined) {
132 if (!(this.options && this.options.allow_alias))
133 throw Error("duplicate id " + id + " in " + this);
134 this.values[name] = id;
136 this.valuesById[this.values[name] = id] = name;
138 this.comments[name] = comment || null;
143 * Removes a value from this enum
144 * @param {string} name Value name
145 * @returns {Enum} `this`
146 * @throws {TypeError} If arguments are invalid
147 * @throws {Error} If `name` is not a name of this enum
149 Enum.prototype.remove = function remove(name) {
151 if (!util.isString(name))
152 throw TypeError("name must be a string");
154 var val = this.values[name];
156 throw Error("name '" + name + "' does not exist in " + this);
158 delete this.valuesById[val];
159 delete this.values[name];
160 delete this.comments[name];
166 * Tests if the specified id is reserved.
167 * @param {number} id Id to test
168 * @returns {boolean} `true` if reserved, otherwise `false`
170 Enum.prototype.isReservedId = function isReservedId(id) {
171 return Namespace.isReservedId(this.reserved, id);
175 * Tests if the specified name is reserved.
176 * @param {string} name Name to test
177 * @returns {boolean} `true` if reserved, otherwise `false`
179 Enum.prototype.isReservedName = function isReservedName(name) {
180 return Namespace.isReservedName(this.reserved, name);