mapfield.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. "use strict";
  2. module.exports = MapField;
  3. // extends Field
  4. var Field = require("./field");
  5. ((MapField.prototype = Object.create(Field.prototype)).constructor = MapField).className = "MapField";
  6. var types = require("./types"),
  7. util = require("./util");
  8. /**
  9. * Constructs a new map field instance.
  10. * @classdesc Reflected map field.
  11. * @extends FieldBase
  12. * @constructor
  13. * @param {string} name Unique name within its namespace
  14. * @param {number} id Unique id within its namespace
  15. * @param {string} keyType Key type
  16. * @param {string} type Value type
  17. * @param {Object.<string,*>} [options] Declared options
  18. * @param {string} [comment] Comment associated with this field
  19. */
  20. function MapField(name, id, keyType, type, options, comment) {
  21. Field.call(this, name, id, type, undefined, undefined, options, comment);
  22. /* istanbul ignore if */
  23. if (!util.isString(keyType))
  24. throw TypeError("keyType must be a string");
  25. /**
  26. * Key type.
  27. * @type {string}
  28. */
  29. this.keyType = keyType; // toJSON, marker
  30. /**
  31. * Resolved key type if not a basic type.
  32. * @type {ReflectionObject|null}
  33. */
  34. this.resolvedKeyType = null;
  35. // Overrides Field#map
  36. this.map = true;
  37. }
  38. /**
  39. * Map field descriptor.
  40. * @interface IMapField
  41. * @extends {IField}
  42. * @property {string} keyType Key type
  43. */
  44. /**
  45. * Extension map field descriptor.
  46. * @interface IExtensionMapField
  47. * @extends IMapField
  48. * @property {string} extend Extended type
  49. */
  50. /**
  51. * Constructs a map field from a map field descriptor.
  52. * @param {string} name Field name
  53. * @param {IMapField} json Map field descriptor
  54. * @returns {MapField} Created map field
  55. * @throws {TypeError} If arguments are invalid
  56. */
  57. MapField.fromJSON = function fromJSON(name, json) {
  58. return new MapField(name, json.id, json.keyType, json.type, json.options, json.comment);
  59. };
  60. /**
  61. * Converts this map field to a map field descriptor.
  62. * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
  63. * @returns {IMapField} Map field descriptor
  64. */
  65. MapField.prototype.toJSON = function toJSON(toJSONOptions) {
  66. var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
  67. return util.toObject([
  68. "keyType" , this.keyType,
  69. "type" , this.type,
  70. "id" , this.id,
  71. "extend" , this.extend,
  72. "options" , this.options,
  73. "comment" , keepComments ? this.comment : undefined
  74. ]);
  75. };
  76. /**
  77. * @override
  78. */
  79. MapField.prototype.resolve = function resolve() {
  80. if (this.resolved)
  81. return this;
  82. // Besides a value type, map fields have a key type that may be "any scalar type except for floating point types and bytes"
  83. if (types.mapKey[this.keyType] === undefined)
  84. throw Error("invalid key type: " + this.keyType);
  85. return Field.prototype.resolve.call(this);
  86. };
  87. /**
  88. * Map field decorator (TypeScript).
  89. * @name MapField.d
  90. * @function
  91. * @param {number} fieldId Field id
  92. * @param {"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"bool"|"string"} fieldKeyType Field key type
  93. * @param {"double"|"float"|"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"bool"|"string"|"bytes"|Object|Constructor<{}>} fieldValueType Field value type
  94. * @returns {FieldDecorator} Decorator function
  95. * @template T extends { [key: string]: number | Long | string | boolean | Uint8Array | Buffer | number[] | Message<{}> }
  96. */
  97. MapField.d = function decorateMapField(fieldId, fieldKeyType, fieldValueType) {
  98. // submessage value: decorate the submessage and use its name as the type
  99. if (typeof fieldValueType === "function")
  100. fieldValueType = util.decorateType(fieldValueType).name;
  101. // enum reference value: create a reflected copy of the enum and keep reuseing it
  102. else if (fieldValueType && typeof fieldValueType === "object")
  103. fieldValueType = util.decorateEnum(fieldValueType).name;
  104. return function mapFieldDecorator(prototype, fieldName) {
  105. util.decorateType(prototype.constructor)
  106. .add(new MapField(fieldName, fieldId, fieldKeyType, fieldValueType));
  107. };
  108. };