UNPKG

@zedux/atoms

Version:

A Molecular State Engine for React

106 lines (105 loc) 4.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IdGenerator = void 0; const core_1 = require("@zedux/core"); const AtomInstanceBase_1 = require("./instances/AtomInstanceBase"); /** * When using SSR, only graph node ids should be generated (via * `generateNodeId`). It is okay for AtomSelector ids to be generated during * SSR, but id'd selectors won't be hydratable on the client since those ids are * not generated predictably (selectors shouldn't be hydrated anyway). Ecosystem * ids must be set manually. */ class IdGenerator { constructor() { this.idCounter = 0; /** * Cache function and class instance references that get passed as params to * atoms or AtomSelectors. Map them to a unique, serializable id. Use a * WeakMap so we don't hold on to anything here */ this.weakCache = new WeakMap(); /** * Generate an id that is guaranteed to be unique in this ecosystem and * pretty-much-guaranteed to be unique globally. * * This method and `IdGenerator#now()` are the only methods in Zedux that * produce random values. * * Override these when testing to create reproducible graphs/dehydrations that * can be used easily in snapshot testing. See our setup in the Zedux repo at * `<repo root>/packages/react/test/utils/ecosystem.ts` for an example. */ this.generateId = (prefix) => // we can slice from 2 to 12 if needed, but keeping it short for now: `${prefix}-${++this.idCounter}${Math.random().toString(36).slice(2, 8)}`; } generateNodeId() { return this.generateId('no'); } /** * Turn an array of anything into a predictable string. If any item is an atom * instance, it will be serialized as the instance's id. If * acceptComplexParams is true, map class instances and functions to a * consistent id for the reference. * * Note that recursive objects are not supported - they would add way too much * overhead here and are really just unnecessary. */ hashParams(params, acceptComplexParams) { return JSON.stringify(params, (_, param) => { if ((0, core_1.is)(param, AtomInstanceBase_1.AtomInstanceBase)) return param.id; if (!param) return param; if (!(0, core_1.isPlainObject)(param)) { if (!acceptComplexParams || Array.isArray(param)) return param; if (typeof param === 'function') return this.cacheFn(param); if (typeof (param === null || param === void 0 ? void 0 : param.constructor) === 'function') { return this.cacheClass(param); } return param; // let engine try to resolve it or throw the error } return Object.keys(param) .sort() .reduce((result, key) => { result[key] = param[key]; return result; }, {}); }); } /** * Generate a timestamp. Pass true to make it a high res timestamp if possible * * This method and `IdGenerator#generateId()` are the only methods in Zedux * that produce random values. * * Override these when testing to create reproducible graphs/dehydrations that * can be used easily in snapshot testing. See our setup in the Zedux repo at * `<repo root>/packages/react/test/utils/ecosystem.ts` for an example. */ now(highRes) { return highRes && typeof performance !== 'undefined' ? performance.now() : Date.now(); } cacheClass(instance) { let id = this.weakCache.get(instance); if (id) return id; id = this.generateId(instance.constructor.name || 'UnknownClass'); this.weakCache.set(instance, id); return id; } cacheFn(fn) { let id = this.weakCache.get(fn); if (id) return id; id = this.generateId(fn.name || 'anonFn'); this.weakCache.set(fn, id); return id; } } exports.IdGenerator = IdGenerator;