UNPKG

reselect

Version:
552 lines (543 loc) 18.9 kB
var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; // src/devModeChecks/cacheSizeCheck.ts var CACHE_SIZE_CHECK_THRESHOLD = 1e3; var runCacheSizeCheck = (cacheSize, funcName) => { let stack = void 0; try { throw new Error(); } catch (e) { ; ({ stack } = e); } console.warn( `A function memoized with weakMapMemoize${funcName ? ` (\`${funcName}\`)` : ""} has seen over ${cacheSize} distinct values for the same primitive argument position. Results keyed by primitive arguments are held strongly and are only released by \`clearCache()\`, so this cache will keep growing for as long as the function keeps seeing new values. If it is called with ever-changing primitives (ids, offsets, timestamps), pass the \`maxSize\` option to bound the cache, switch to \`lruMemoize\`, or call \`.clearCache()\` at a suitable point. See https://reselect.js.org/api/development-only-checks#cachesizecheck for details.`, { stack } ); }; // src/devModeChecks/setGlobalDevModeChecks.ts var globalDevModeChecks = { inputStabilityCheck: "once", identityFunctionCheck: "once", cacheSizeCheck: "once" }; var setGlobalDevModeChecks = (devModeChecks) => { Object.assign(globalDevModeChecks, devModeChecks); }; // src/weakMapMemoize.ts var StrongRef = class { constructor(value) { this.value = value; } deref() { return this.value; } }; var getWeakRef = () => typeof WeakRef === "undefined" ? StrongRef : WeakRef; var Ref = /* @__PURE__ */ getWeakRef(); var UNTERMINATED = 0; var TERMINATED = 1; function createCacheNode() { return { s: UNTERMINATED, v: void 0, o: null, p: null }; } function maybeDeref(r) { if (r instanceof Ref) { return r.deref(); } return r; } function weakMapMemoize(func, options = {}) { let fnNode = createCacheNode(); const { resultEqualityCheck, maxSize } = options; const useGenerations = maxSize !== void 0; if (useGenerations && (!Number.isInteger(maxSize) || maxSize < 1)) { throw new TypeError( `maxSize must be a positive integer, received: ${maxSize}` ); } let prevNode = null; let insertionCount = 0; let lastResult; let resultsCount = 0; let hasWarnedAboutCacheSize = false; function maybeFlipGenerations() { if (insertionCount >= maxSize) { prevNode = fnNode; fnNode = createCacheNode(); insertionCount = 0; } } function memoized() { let cacheNode = fnNode; const { length } = arguments; for (let i = 0, l = length; i < l; i++) { const arg = arguments[i]; if (typeof arg === "function" || typeof arg === "object" && arg !== null) { let objectCache = cacheNode.o; if (objectCache === null) { cacheNode.o = objectCache = /* @__PURE__ */ new WeakMap(); } const objectNode = objectCache.get(arg); if (objectNode === void 0) { cacheNode = createCacheNode(); objectCache.set(arg, cacheNode); } else { cacheNode = objectNode; } } else { let primitiveCache = cacheNode.p; if (primitiveCache === null) { cacheNode.p = primitiveCache = /* @__PURE__ */ new Map(); } const primitiveNode = primitiveCache.get(arg); if (primitiveNode === void 0) { cacheNode = createCacheNode(); primitiveCache.set(arg, cacheNode); insertionCount++; if (process.env.NODE_ENV !== "production") { if (primitiveCache.size > CACHE_SIZE_CHECK_THRESHOLD) { const { cacheSizeCheck } = globalDevModeChecks; if (cacheSizeCheck === "always" || cacheSizeCheck === "once" && !hasWarnedAboutCacheSize) { hasWarnedAboutCacheSize = true; runCacheSizeCheck(primitiveCache.size, func.name); } } } } else { cacheNode = primitiveNode; } } } if (cacheNode.s === TERMINATED) { return cacheNode.v; } if (prevNode !== null) { let prevCacheNode = prevNode; for (let i = 0, l = length; i < l; i++) { const arg = arguments[i]; let next; if (typeof arg === "function" || typeof arg === "object" && arg !== null) { const prevObjectCache = prevCacheNode.o; next = prevObjectCache !== null ? prevObjectCache.get(arg) : void 0; } else { const prevPrimitiveCache = prevCacheNode.p; next = prevPrimitiveCache !== null ? prevPrimitiveCache.get(arg) : void 0; } if (next === void 0) { prevCacheNode = null; break; } prevCacheNode = next; } if (prevCacheNode !== null && prevCacheNode.s === TERMINATED) { const promotedNode = cacheNode; promotedNode.s = TERMINATED; promotedNode.v = prevCacheNode.v; maybeFlipGenerations(); return prevCacheNode.v; } } const terminatedNode = cacheNode; let result = func.apply(null, arguments); resultsCount++; if (resultEqualityCheck) { const lastResultValue = maybeDeref(lastResult); if (lastResultValue != null && resultEqualityCheck(lastResultValue, result)) { result = lastResultValue; resultsCount !== 0 && resultsCount--; } const needsWeakRef = typeof result === "object" && result !== null || typeof result === "function"; lastResult = needsWeakRef ? /* @__PURE__ */ new Ref(result) : result; } terminatedNode.s = TERMINATED; terminatedNode.v = result; if (useGenerations) { maybeFlipGenerations(); } return result; } memoized.clearCache = () => { fnNode = createCacheNode(); prevNode = null; insertionCount = 0; memoized.resetResultsCount(); if (process.env.NODE_ENV !== "production") { hasWarnedAboutCacheSize = false; } }; memoized.resultsCount = () => resultsCount; memoized.resetResultsCount = () => { resultsCount = 0; }; return memoized; } // src/devModeChecks/identityFunctionCheck.ts var runIdentityFunctionCheck = (resultFunc, inputSelectorsResults, outputSelectorResult) => { if (inputSelectorsResults.length === 1 && inputSelectorsResults[0] === outputSelectorResult) { let isInputSameAsOutput = false; try { const emptyObject = {}; if (resultFunc(emptyObject) === emptyObject) isInputSameAsOutput = true; } catch (e) { } if (isInputSameAsOutput) { let stack = void 0; try { throw new Error(); } catch (e) { ; ({ stack } = e); } console.warn( "The result function returned its own inputs without modification. e.g\n`createSelector([state => state.todos], todos => todos)`\nThis could lead to inefficient memoization and unnecessary re-renders.\nEnsure transformation logic is in the result function, and extraction logic is in the input selectors.", { stack } ); } } }; // src/devModeChecks/inputStabilityCheck.ts var withoutResultEqualityCheck = (option) => { if (option === null || typeof option !== "object" || !("resultEqualityCheck" in option)) { return option; } const optionCopy = __spreadValues({}, option); delete optionCopy.resultEqualityCheck; return optionCopy; }; var runInputStabilityCheck = (inputSelectorResultsObject, options, inputSelectorArgs) => { const { memoize, memoizeOptions } = options; const { inputSelectorResults, inputSelectorResultsCopy } = inputSelectorResultsObject; const probeMemoizeOptions = []; const { length } = memoizeOptions; for (let i = 0; i < length; i++) { probeMemoizeOptions.push(withoutResultEqualityCheck(memoizeOptions[i])); } const createAnEmptyObject = memoize(() => ({}), ...probeMemoizeOptions); const areInputSelectorResultsEqual = createAnEmptyObject.apply(null, inputSelectorResults) === createAnEmptyObject.apply(null, inputSelectorResultsCopy); if (!areInputSelectorResultsEqual) { let stack = void 0; try { throw new Error(); } catch (e) { ; ({ stack } = e); } console.warn( "An input selector returned a different result when passed same arguments.\nThis means your output selector will likely run more frequently than intended.\nAvoid returning a new reference inside your input selector, e.g.\n`createSelector([state => state.todos.map(todo => todo.id)], todoIds => todoIds.length)`", { arguments: inputSelectorArgs, firstInputs: inputSelectorResults, secondInputs: inputSelectorResultsCopy, stack } ); } }; // src/utils.ts var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND"); function assertIsFunction(func, errorMessage = `expected a function, instead received ${typeof func}`) { if (typeof func !== "function") { throw new TypeError(errorMessage); } } function assertIsObject(object, errorMessage = `expected an object, instead received ${typeof object}`) { if (typeof object !== "object") { throw new TypeError(errorMessage); } } function assertIsArrayOfFunctions(array, errorMessage = `expected all items to be functions, instead received the following types: `) { if (!array.every((item) => typeof item === "function")) { const itemTypes = array.map( (item) => typeof item === "function" ? `function ${item.name || "unnamed"}()` : typeof item ).join(", "); throw new TypeError(`${errorMessage}[${itemTypes}]`); } } var ensureIsArray = (item) => { return Array.isArray(item) ? item : [item]; }; function getDependencies(createSelectorArgs) { const dependencies = Array.isArray(createSelectorArgs[0]) ? createSelectorArgs[0] : createSelectorArgs; assertIsArrayOfFunctions( dependencies, `createSelector expects all input-selectors to be functions, but received the following types: ` ); return dependencies; } function collectInputSelectorResults(dependencies, inputSelectorArgs) { const inputSelectorResults = []; const { length } = dependencies; for (let i = 0; i < length; i++) { inputSelectorResults.push(dependencies[i].apply(null, inputSelectorArgs)); } return inputSelectorResults; } // src/createSelectorCreator.ts function createSelectorCreator(memoizeOrOptions, ...memoizeOptionsFromArgs) { const createSelectorCreatorOptions = typeof memoizeOrOptions === "function" ? { memoize: memoizeOrOptions, memoizeOptions: memoizeOptionsFromArgs } : memoizeOrOptions; const createSelector2 = (...createSelectorArgs) => { let recomputations = 0; let dependencyRecomputations = 0; let lastResult; let directlyPassedOptions = {}; let resultFunc = createSelectorArgs.pop(); if (typeof resultFunc === "object") { directlyPassedOptions = resultFunc; resultFunc = createSelectorArgs.pop(); } assertIsFunction( resultFunc, `createSelector expects an output function after the inputs, but received: [${typeof resultFunc}]` ); const combinedOptions = __spreadValues(__spreadValues({}, createSelectorCreatorOptions), directlyPassedOptions); const { memoize, memoizeOptions = [], argsMemoize = weakMapMemoize, argsMemoizeOptions = [] } = combinedOptions; const finalMemoizeOptions = ensureIsArray(memoizeOptions); const finalArgsMemoizeOptions = ensureIsArray(argsMemoizeOptions); const dependencies = getDependencies(createSelectorArgs); const memoizedResultFunc = memoize(function recomputationWrapper() { recomputations++; return resultFunc.apply( null, arguments ); }, ...finalMemoizeOptions); let firstRun = true; const selector = argsMemoize(function dependenciesChecker() { dependencyRecomputations++; const { length } = dependencies; const inputSelectorResults = new Array(length); for (let i = 0; i < length; i++) { inputSelectorResults[i] = dependencies[i].apply(null, arguments); } lastResult = memoizedResultFunc.apply(null, inputSelectorResults); if (process.env.NODE_ENV !== "production") { const { devModeChecks } = combinedOptions; const identityFunctionCheck = devModeChecks !== void 0 && Object.prototype.hasOwnProperty.call( devModeChecks, "identityFunctionCheck" ) ? devModeChecks.identityFunctionCheck : globalDevModeChecks.identityFunctionCheck; const inputStabilityCheck = devModeChecks !== void 0 && Object.prototype.hasOwnProperty.call( devModeChecks, "inputStabilityCheck" ) ? devModeChecks.inputStabilityCheck : globalDevModeChecks.inputStabilityCheck; if (identityFunctionCheck === "always" || identityFunctionCheck === "once" && firstRun) { runIdentityFunctionCheck( resultFunc, inputSelectorResults, lastResult ); } if (inputStabilityCheck === "always" || inputStabilityCheck === "once" && firstRun) { const inputSelectorResultsCopy = collectInputSelectorResults( dependencies, arguments ); runInputStabilityCheck( { inputSelectorResults, inputSelectorResultsCopy }, { memoize, memoizeOptions: finalMemoizeOptions }, arguments ); } if (firstRun) firstRun = false; } return lastResult; }, ...finalArgsMemoizeOptions); return Object.assign(selector, { resultFunc, memoizedResultFunc, dependencies, dependencyRecomputations: () => dependencyRecomputations, resetDependencyRecomputations: () => { dependencyRecomputations = 0; }, lastResult: () => lastResult, recomputations: () => recomputations, resetRecomputations: () => { recomputations = 0; }, memoize, argsMemoize }); }; Object.assign(createSelector2, { withTypes: () => createSelector2 }); return createSelector2; } var createSelector = /* @__PURE__ */ createSelectorCreator(weakMapMemoize); // src/createStructuredSelector.ts var createStructuredSelector = /* @__PURE__ */ Object.assign( (inputSelectorsObject, selectorCreator = createSelector) => { assertIsObject( inputSelectorsObject, `createStructuredSelector expects first argument to be an object where each property is a selector, instead received a ${typeof inputSelectorsObject}` ); const inputSelectorKeys = Object.keys(inputSelectorsObject); const dependencies = inputSelectorKeys.map( (key) => inputSelectorsObject[key] ); const structuredSelector = selectorCreator( dependencies, (...inputSelectorResults) => { return inputSelectorResults.reduce((composition, value, index) => { composition[inputSelectorKeys[index]] = value; return composition; }, {}); } ); return structuredSelector; }, { withTypes: () => createStructuredSelector } ); // src/lruMemoize.ts function createSingletonCache(equals) { let entry; return { get(key) { if (entry && equals(entry.key, key)) { return entry.value; } return NOT_FOUND; }, put(key, value) { entry = { key, value }; }, findMatchingEntry(value, resultEqualityCheck) { const current = entry; return current !== void 0 && resultEqualityCheck(current.value, value) ? current : void 0; }, clear() { entry = void 0; } }; } function createLruCache(maxSize, equals) { let entries = []; function get(key) { const cacheIndex = entries.findIndex((entry) => equals(entry.key, key)); if (cacheIndex > -1) { const entry = entries[cacheIndex]; if (cacheIndex > 0) { entries.splice(cacheIndex, 1); entries.unshift(entry); } return entry.value; } return NOT_FOUND; } function put(key, value) { entries.unshift({ key, value }); if (entries.length > maxSize) { entries.pop(); } } function findMatchingEntry(value, resultEqualityCheck) { const currentEntries = entries; const { length } = currentEntries; for (let i = 0; i < length; i++) { const entry = currentEntries[i]; if (resultEqualityCheck(entry.value, value)) { return entry; } } return void 0; } function clear() { entries = []; } return { get, put, findMatchingEntry, clear }; } var referenceEqualityCheck = (a, b) => a === b; function createCacheKeyComparator(equalityCheck) { return function areArgumentsShallowlyEqual(prev, next) { if (prev === null || next === null || prev.length !== next.length) { return false; } const { length } = prev; for (let i = 0; i < length; i++) { if (!equalityCheck(prev[i], next[i])) { return false; } } return true; }; } function lruMemoize(func, equalityCheckOrOptions) { const providedOptions = typeof equalityCheckOrOptions === "object" ? equalityCheckOrOptions : { equalityCheck: equalityCheckOrOptions }; const { equalityCheck = referenceEqualityCheck, maxSize = 1, resultEqualityCheck } = providedOptions; const comparator = createCacheKeyComparator(equalityCheck); let resultsCount = 0; const cache = maxSize <= 1 ? createSingletonCache(comparator) : createLruCache(maxSize, comparator); function memoized() { let value = cache.get(arguments); if (value === NOT_FOUND) { value = func.apply(null, arguments); resultsCount++; if (resultEqualityCheck) { const matchingEntry = cache.findMatchingEntry( value, resultEqualityCheck ); if (matchingEntry) { value = matchingEntry.value; resultsCount !== 0 && resultsCount--; } } cache.put(arguments, value); } return value; } memoized.clearCache = () => { cache.clear(); memoized.resetResultsCount(); }; memoized.resultsCount = () => resultsCount; memoized.resetResultsCount = () => { resultsCount = 0; }; return memoized; } export { createSelector, createSelectorCreator, createStructuredSelector, lruMemoize, referenceEqualityCheck, setGlobalDevModeChecks, weakMapMemoize }; //# sourceMappingURL=reselect.legacy-esm.js.map