File size: 6,199 Bytes
c1b3a0c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
"use strict";
module.exports = Enum;
// extends ReflectionObject
var ReflectionObject = require("./object");
((Enum.prototype = Object.create(ReflectionObject.prototype)).constructor = Enum).className = "Enum";
var Namespace = require("./namespace"),
util = require("./util");
/**
* Constructs a new enum instance.
* @classdesc Reflected enum.
* @extends ReflectionObject
* @constructor
* @param {string} name Unique name within its namespace
* @param {Object.<string,number>} [values] Enum values as an object, by name
* @param {Object.<string,*>} [options] Declared options
* @param {string} [comment] The comment for this enum
* @param {Object.<string,string>} [comments] The value comments for this enum
* @param {Object.<string,Object<string,*>>|undefined} [valuesOptions] The value options for this enum
*/
function Enum(name, values, options, comment, comments, valuesOptions) {
ReflectionObject.call(this, name, options);
if (values && typeof values !== "object")
throw TypeError("values must be an object");
/**
* Enum values by id.
* @type {Object.<number,string>}
*/
this.valuesById = {};
/**
* Enum values by name.
* @type {Object.<string,number>}
*/
this.values = Object.create(this.valuesById); // toJSON, marker
/**
* Enum comment text.
* @type {string|null}
*/
this.comment = comment;
/**
* Value comment texts, if any.
* @type {Object.<string,string>}
*/
this.comments = comments || {};
/**
* Values options, if any
* @type {Object<string, Object<string, *>>|undefined}
*/
this.valuesOptions = valuesOptions;
/**
* Reserved ranges, if any.
* @type {Array.<number[]|string>}
*/
this.reserved = undefined; // toJSON
// Note that values inherit valuesById on their prototype which makes them a TypeScript-
// compatible enum. This is used by pbts to write actual enum definitions that work for
// static and reflection code alike instead of emitting generic object definitions.
if (values)
for (var keys = Object.keys(values), i = 0; i < keys.length; ++i)
if (typeof values[keys[i]] === "number") // use forward entries only
this.valuesById[ this.values[keys[i]] = values[keys[i]] ] = keys[i];
}
/**
* Enum descriptor.
* @interface IEnum
* @property {Object.<string,number>} values Enum values
* @property {Object.<string,*>} [options] Enum options
*/
/**
* Constructs an enum from an enum descriptor.
* @param {string} name Enum name
* @param {IEnum} json Enum descriptor
* @returns {Enum} Created enum
* @throws {TypeError} If arguments are invalid
*/
Enum.fromJSON = function fromJSON(name, json) {
var enm = new Enum(name, json.values, json.options, json.comment, json.comments);
enm.reserved = json.reserved;
return enm;
};
/**
* Converts this enum to an enum descriptor.
* @param {IToJSONOptions} [toJSONOptions] JSON conversion options
* @returns {IEnum} Enum descriptor
*/
Enum.prototype.toJSON = function toJSON(toJSONOptions) {
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
return util.toObject([
"options" , this.options,
"valuesOptions" , this.valuesOptions,
"values" , this.values,
"reserved" , this.reserved && this.reserved.length ? this.reserved : undefined,
"comment" , keepComments ? this.comment : undefined,
"comments" , keepComments ? this.comments : undefined
]);
};
/**
* Adds a value to this enum.
* @param {string} name Value name
* @param {number} id Value id
* @param {string} [comment] Comment, if any
* @param {Object.<string, *>|undefined} [options] Options, if any
* @returns {Enum} `this`
* @throws {TypeError} If arguments are invalid
* @throws {Error} If there is already a value with this name or id
*/
Enum.prototype.add = function add(name, id, comment, options) {
// utilized by the parser but not by .fromJSON
if (!util.isString(name))
throw TypeError("name must be a string");
if (!util.isInteger(id))
throw TypeError("id must be an integer");
if (this.values[name] !== undefined)
throw Error("duplicate name '" + name + "' in " + this);
if (this.isReservedId(id))
throw Error("id " + id + " is reserved in " + this);
if (this.isReservedName(name))
throw Error("name '" + name + "' is reserved in " + this);
if (this.valuesById[id] !== undefined) {
if (!(this.options && this.options.allow_alias))
throw Error("duplicate id " + id + " in " + this);
this.values[name] = id;
} else
this.valuesById[this.values[name] = id] = name;
if (options) {
if (this.valuesOptions === undefined)
this.valuesOptions = {};
this.valuesOptions[name] = options || null;
}
this.comments[name] = comment || null;
return this;
};
/**
* Removes a value from this enum
* @param {string} name Value name
* @returns {Enum} `this`
* @throws {TypeError} If arguments are invalid
* @throws {Error} If `name` is not a name of this enum
*/
Enum.prototype.remove = function remove(name) {
if (!util.isString(name))
throw TypeError("name must be a string");
var val = this.values[name];
if (val == null)
throw Error("name '" + name + "' does not exist in " + this);
delete this.valuesById[val];
delete this.values[name];
delete this.comments[name];
if (this.valuesOptions)
delete this.valuesOptions[name];
return this;
};
/**
* Tests if the specified id is reserved.
* @param {number} id Id to test
* @returns {boolean} `true` if reserved, otherwise `false`
*/
Enum.prototype.isReservedId = function isReservedId(id) {
return Namespace.isReservedId(this.reserved, id);
};
/**
* Tests if the specified name is reserved.
* @param {string} name Name to test
* @returns {boolean} `true` if reserved, otherwise `false`
*/
Enum.prototype.isReservedName = function isReservedName(name) {
return Namespace.isReservedName(this.reserved, name);
};
|