UNPKG

value-object-cache

Version:

A value object cache that can be used to make value objects behave like primitive types, i.e. if two variables `a` and `b` point to instances of the same class and have the same value, then `a === b`, otherwise `a !== b`.

144 lines (143 loc) 6.29 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __typeError = (msg) => { throw TypeError(msg); }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); // src/index.ts var src_exports = {}; __export(src_exports, { ValueObject: () => ValueObject, isPrimitive: () => isPrimitive, isValue: () => isValue, isValueArray: () => isValueArray, isValueObject: () => isValueObject, valueObjectCache: () => valueObjectCache }); module.exports = __toCommonJS(src_exports); var VALUE_OBJECT_BRAND = Symbol(); var _a; _a = VALUE_OBJECT_BRAND; var ValueObject = class { constructor(props, values) { this.props = props; this[_a] = true; Object.freeze(this.props); return valueObjectCache.getObject(this.constructor, values, () => this); } }; function isPrimitive(x) { return typeof x !== "function" && (typeof x !== "object" || x === null); } function isValueArray(x) { return Array.isArray(x) && x.every(isValue); } function isValueObject(x) { return x instanceof ValueObject; } function isValue(x) { return isPrimitive(x) || isValueArray(x) || isValueObject(x); } var _rootNode, _finalizationRegistry, _ValueObjectCache_instances, get_fn, _a2; var valueObjectCache = new (_a2 = class { constructor() { __privateAdd(this, _ValueObjectCache_instances); __privateAdd(this, _rootNode, { children: null, instanceRef: null }); __privateAdd(this, _finalizationRegistry, new FinalizationRegistry((path) => { var _a3, _b; const walkedNodes = [ { currentNode: __privateGet(this, _rootNode), parentNode: null, parentKey: null } ]; let node = __privateGet(this, _rootNode); for (const key of path) { const childNode = (_a3 = node.children) == null ? void 0 : _a3.get(key); if (!childNode) break; walkedNodes.push({ currentNode: childNode, parentNode: node, parentKey: key }); node = childNode; } walkedNodes.reverse(); for (const { currentNode, parentNode, parentKey } of walkedNodes) { if (currentNode.children && !currentNode.children.size) currentNode.children = null; if (currentNode.instanceRef && !currentNode.instanceRef.deref()) currentNode.instanceRef = null; if (currentNode.children || currentNode.instanceRef) break; (_b = parentNode == null ? void 0 : parentNode.children) == null ? void 0 : _b.delete(parentKey); } })); } /** Look for an instance of the provided class constructor matching the provided values. If a matching instance is * found then it is returned, otherwise the factory function is called to create a new instance, which is then stored * in the cache and returned - all future calls to this method made with the same constructor and values will return * this instance until it is garbage-collected. */ getObject(constructor, values, factory) { return __privateMethod(this, _ValueObjectCache_instances, get_fn).call(this, constructor, values.map((v) => this.getValue(v)), () => Object.freeze(factory())); } /** Look for an {@link Array} containing a specific list of values in the cache. If a matching {@link Array} is found * then it is returned, otherwise a new {@link Array} is stored in the cache and returned. All returned arrays are * frozen (readonly). */ getArray(values) { const array = values.map((v) => this.getValue(v)); return __privateMethod(this, _ValueObjectCache_instances, get_fn).call(this, array.constructor, array, () => Object.freeze(array)); } getValue(value) { if (isPrimitive(value)) { return value; } else if (Array.isArray(value)) { return this.getArray(value); } else if (isValueObject(value)) { return value; } else { throw new TypeError("Invalid value type: a value must be a primitive, an array, or a ValueObject."); } } }, _rootNode = new WeakMap(), _finalizationRegistry = new WeakMap(), _ValueObjectCache_instances = new WeakSet(), get_fn = function(constructor, values, factory) { var _a3; const path = [constructor, ...values]; let node = __privateGet(this, _rootNode); for (const key of path) { if (!node.children) node.children = /* @__PURE__ */ new Map(); let childNode = node.children.get(key); if (!childNode) { childNode = { children: null, instanceRef: null }; node.children.set(key, childNode); } node = childNode; } const cachedInstance = (_a3 = node.instanceRef) == null ? void 0 : _a3.deref(); if (cachedInstance) return cachedInstance; const instance = factory(); if (instance.constructor !== constructor) { throw new TypeError("factory must return an instance of the provided constructor"); } node.instanceRef = new WeakRef(instance); __privateGet(this, _finalizationRegistry).register(instance, path); return instance; }, _a2)(); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ValueObject, isPrimitive, isValue, isValueArray, isValueObject, valueObjectCache }); //# sourceMappingURL=index.js.map