Bez popisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

enum.js 5.4KB

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