map.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { setSafeProperty, hasSafeProperty, getSafeProperty } from './customs.js';
  2. import { isObject } from './is.js';
  3. /**
  4. * A map facade on a bare object.
  5. *
  6. * The small number of methods needed to implement a scope,
  7. * forwarding on to the SafeProperty functions. Over time, the codebase
  8. * will stop using this method, as all objects will be Maps, rather than
  9. * more security prone objects.
  10. */
  11. export class ObjectWrappingMap {
  12. constructor(object) {
  13. this.wrappedObject = object;
  14. }
  15. keys() {
  16. return Object.keys(this.wrappedObject);
  17. }
  18. get(key) {
  19. return getSafeProperty(this.wrappedObject, key);
  20. }
  21. set(key, value) {
  22. setSafeProperty(this.wrappedObject, key, value);
  23. return this;
  24. }
  25. has(key) {
  26. return hasSafeProperty(this.wrappedObject, key);
  27. }
  28. }
  29. /**
  30. * Creates an empty map, or whatever your platform's polyfill is.
  31. *
  32. * @returns an empty Map or Map like object.
  33. */
  34. export function createEmptyMap() {
  35. return new Map();
  36. }
  37. /**
  38. * Creates a Map from the given object.
  39. *
  40. * @param { Map | { [key: string]: unknown } | undefined } mapOrObject
  41. * @returns
  42. */
  43. export function createMap(mapOrObject) {
  44. if (!mapOrObject) {
  45. return createEmptyMap();
  46. }
  47. if (isMap(mapOrObject)) {
  48. return mapOrObject;
  49. }
  50. if (isObject(mapOrObject)) {
  51. return new ObjectWrappingMap(mapOrObject);
  52. }
  53. throw new Error('createMap can create maps from objects or Maps');
  54. }
  55. /**
  56. * Unwraps a map into an object.
  57. *
  58. * @param {Map} map
  59. * @returns { [key: string]: unknown }
  60. */
  61. export function toObject(map) {
  62. if (map instanceof ObjectWrappingMap) {
  63. return map.wrappedObject;
  64. }
  65. var object = {};
  66. for (var key of map.keys()) {
  67. var value = map.get(key);
  68. setSafeProperty(object, key, value);
  69. }
  70. return object;
  71. }
  72. /**
  73. * Returns `true` if the passed object appears to be a Map (i.e. duck typing).
  74. *
  75. * Methods looked for are `get`, `set`, `keys` and `has`.
  76. *
  77. * @param {Map | object} object
  78. * @returns
  79. */
  80. export function isMap(object) {
  81. // We can use the fast instanceof, or a slower duck typing check.
  82. // The duck typing method needs to cover enough methods to not be confused with DenseMatrix.
  83. if (!object) {
  84. return false;
  85. }
  86. return object instanceof Map || object instanceof ObjectWrappingMap || typeof object.set === 'function' && typeof object.get === 'function' && typeof object.keys === 'function' && typeof object.has === 'function';
  87. }
  88. /**
  89. * Copies the contents of key-value pairs from each `objects` in to `map`.
  90. *
  91. * Object is `objects` can be a `Map` or object.
  92. *
  93. * This is the `Map` analog to `Object.assign`.
  94. */
  95. export function assign(map) {
  96. for (var _len = arguments.length, objects = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  97. objects[_key - 1] = arguments[_key];
  98. }
  99. for (var args of objects) {
  100. if (!args) {
  101. continue;
  102. }
  103. if (isMap(args)) {
  104. for (var key of args.keys()) {
  105. map.set(key, args.get(key));
  106. }
  107. } else if (isObject(args)) {
  108. for (var _key2 of Object.keys(args)) {
  109. map.set(_key2, args[_key2]);
  110. }
  111. }
  112. }
  113. return map;
  114. }