reselect-kit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +473 -0
  3. package/dist/cjs/index.js +6 -0
  4. package/dist/cjs/reselectKit.development.cjs +683 -0
  5. package/dist/cjs/reselectKit.development.cjs.map +1 -0
  6. package/dist/cjs/reselectKit.production.min.cjs +2 -0
  7. package/dist/cjs/reselectKit.production.min.cjs.map +1 -0
  8. package/dist/reselectKit.d.ts +248 -0
  9. package/dist/reselectKit.mjs +678 -0
  10. package/dist/reselectKit.mjs.map +1 -0
  11. package/package.json +70 -0
  12. package/src/__data__/state.ts +97 -0
  13. package/src/__tests__/createAdaptedSelector.test.ts +134 -0
  14. package/src/__tests__/createBoundSelector.test.ts +351 -0
  15. package/src/__tests__/createCachedSequenceSelector.test.ts +24 -0
  16. package/src/__tests__/createCachedStructuredSelector.test.ts +29 -0
  17. package/src/__tests__/createChainSelector.test.ts +404 -0
  18. package/src/__tests__/createEmptySelector.test.ts +99 -0
  19. package/src/__tests__/createPathSelector.test.ts +81 -0
  20. package/src/__tests__/createPropSelector.test.ts +36 -0
  21. package/src/__tests__/createSegmentSelector.test.ts +31 -0
  22. package/src/__tests__/createSequenceSelector.test.ts +62 -0
  23. package/src/_helpers/__tests__/arePathsEqual.test.ts +27 -0
  24. package/src/_helpers/__tests__/getObjectPaths.test.ts +56 -0
  25. package/src/_helpers/__tests__/temporaryAssign.test.ts +59 -0
  26. package/src/_helpers/arePathsEqual.ts +15 -0
  27. package/src/_helpers/defineDynamicSelectorName.ts +10 -0
  28. package/src/_helpers/generateSelectorKey.ts +15 -0
  29. package/src/_helpers/getObjectPaths.ts +13 -0
  30. package/src/_helpers/getSelectorName.ts +7 -0
  31. package/src/_helpers/isCachedSelector.ts +9 -0
  32. package/src/_helpers/isObject.ts +3 -0
  33. package/src/_helpers/stringifyFunction.ts +3 -0
  34. package/src/_helpers/temporaryAssign.ts +80 -0
  35. package/src/_hooks/__tests__/useMemoWith.test.ts +31 -0
  36. package/src/_hooks/__tests__/useSelector.test.ts +87 -0
  37. package/src/_hooks/useMemoWith.ts +11 -0
  38. package/src/_hooks/useSelector.ts +34 -0
  39. package/src/cache/TreeCache.ts +126 -0
  40. package/src/cache/__tests__/TreeCacheObject.test.ts +188 -0
  41. package/src/cache/__tests__/intervalMapCache.test.ts +133 -0
  42. package/src/cache/intervalMapCache.ts +97 -0
  43. package/src/createAdaptedSelector.ts +75 -0
  44. package/src/createBoundSelector.ts +197 -0
  45. package/src/createCachedSequenceSelector.ts +18 -0
  46. package/src/createCachedStructuredSelector.ts +44 -0
  47. package/src/createChainSelector.ts +230 -0
  48. package/src/createEmptySelector.ts +27 -0
  49. package/src/createPathSelector.ts +208 -0
  50. package/src/createPropSelector.ts +28 -0
  51. package/src/createSegmentSelector.ts +6 -0
  52. package/src/createSequenceSelector.ts +15 -0
  53. package/src/createStructuredSelector.ts +3 -0
  54. package/src/debug/__tests__/debug.test.ts +20 -0
  55. package/src/debug/debug.ts +7 -0
  56. package/src/debug/withDebugName.ts +28 -0
  57. package/src/index.ts +26 -0
  58. package/src/keys/__tests__/arrayComposeKeySelectors.test.ts +52 -0
  59. package/src/keys/__tests__/createKeySelectorCreator.test.ts +246 -0
  60. package/src/keys/__tests__/stringComposeKeySelectors.test.ts +52 -0
  61. package/src/keys/arrayComposeKeySelectors.ts +20 -0
  62. package/src/keys/createKeySelectorComposer.ts +68 -0
  63. package/src/keys/createKeySelectorCreator.ts +106 -0
  64. package/src/keys/defaultKeySelector.ts +1 -0
  65. package/src/keys/stringComposeKeySelectors.ts +15 -0
  66. package/src/types.ts +43 -0
  67. package/src/vitest-globals.d.ts +1 -0
@@ -0,0 +1,683 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _veksa_re_reselect = require("@veksa/re-reselect");
3
+ let _veksa_reselect = require("@veksa/reselect");
4
+ let _veksa_react_redux = require("@veksa/react-redux");
5
+ let react = require("react");
6
+ //#region src/createSegmentSelector.ts
7
+ function createSegmentSelector(fn, initial) {
8
+ return (state) => fn(state) ?? initial;
9
+ }
10
+ //#endregion
11
+ //#region src/_helpers/isObject.ts
12
+ const isObject = (value) => {
13
+ return value !== null && typeof value === "object";
14
+ };
15
+ //#endregion
16
+ //#region src/_helpers/defineDynamicSelectorName.ts
17
+ const defineDynamicSelectorName = (selector, selectorNameGetter) => {
18
+ let overriddenSelectorName;
19
+ Object.defineProperty(selector, "selectorName", {
20
+ configurable: true,
21
+ get: () => overriddenSelectorName ?? selectorNameGetter(),
22
+ set: (value) => {
23
+ overriddenSelectorName = value;
24
+ }
25
+ });
26
+ };
27
+ //#endregion
28
+ //#region src/debug/debug.ts
29
+ let debugMode = false;
30
+ const isDebugMode = () => debugMode;
31
+ const setDebugMode = (value) => {
32
+ debugMode = value;
33
+ };
34
+ //#endregion
35
+ //#region src/debug/withDebugName.ts
36
+ /**
37
+ * Runs `callback` only outside production and only while debug mode is enabled.
38
+ * Centralizes the `NODE_ENV` / `isDebugMode` guard that the selector factories
39
+ * would otherwise repeat around every debug-name assignment.
40
+ */
41
+ const runInDebug = (callback) => {
42
+ /* istanbul ignore else */
43
+ if (isDebugMode()) callback();
44
+ };
45
+ /**
46
+ * Assigns a lazily-computed debug name to `selector`, guarded by
47
+ * {@link runInDebug}. Covers the common single-name case; use `runInDebug`
48
+ * directly when a block needs to name several selectors at once.
49
+ */
50
+ const withDebugName = (selector, selectorNameGetter) => {
51
+ runInDebug(() => {
52
+ defineDynamicSelectorName(selector, selectorNameGetter);
53
+ });
54
+ };
55
+ //#endregion
56
+ //#region src/_helpers/getSelectorName.ts
57
+ const getSelectorName = (selector) => {
58
+ if ("selectorName" in selector && selector.selectorName) return selector.selectorName;
59
+ return selector.name;
60
+ };
61
+ //#endregion
62
+ //#region src/createPathSelector.ts
63
+ const defaultVoidFunction = () => {};
64
+ /** @internal */
65
+ const innerCreatePathSelector = (baseSelector, path = [], applyMeta = defaultVoidFunction) => {
66
+ const pathLength = path.length;
67
+ const proxyTarget = (defaultValue) => {
68
+ function resultSelector(state, props) {
69
+ let result;
70
+ if (arguments.length === 2) result = baseSelector(state, props);
71
+ else if (arguments.length === 1) result = baseSelector(state);
72
+ else result = baseSelector.apply(null, arguments);
73
+ for (let i = 0; i < pathLength && isObject(result); i += 1) result = result[path[i]];
74
+ return result === void 0 ? defaultValue : result;
75
+ }
76
+ Object.assign(resultSelector, baseSelector, { path });
77
+ resultSelector.dependencies = [baseSelector];
78
+ applyMeta(resultSelector);
79
+ withDebugName(resultSelector, () => {
80
+ return [getSelectorName(baseSelector), ...path].join(".");
81
+ });
82
+ return resultSelector;
83
+ };
84
+ return new Proxy(proxyTarget, { get: (_target, key) => {
85
+ return innerCreatePathSelector(baseSelector, [...path, String(key)], applyMeta);
86
+ } });
87
+ };
88
+ function createPathSelector(baseSelector) {
89
+ return innerCreatePathSelector(baseSelector);
90
+ }
91
+ //#endregion
92
+ //#region src/createPropSelector.ts
93
+ const propSelectorSymbol = Symbol.for("PropSelector");
94
+ const isPropSelector = (selector) => {
95
+ return selector instanceof Object && propSelectorSymbol in selector;
96
+ };
97
+ function createPropSelector() {
98
+ const propsSelector = (_state, props) => props;
99
+ const applyMeta = (selector) => {
100
+ Object.defineProperty(selector, propSelectorSymbol, { value: true });
101
+ };
102
+ return innerCreatePathSelector(propsSelector, [], applyMeta);
103
+ }
104
+ //#endregion
105
+ //#region src/keys/createKeySelectorComposer.ts
106
+ const composedKeySelectorSymbol = Symbol.for("ComposedKeySelector");
107
+ function isComposedKeySelector(keySelector) {
108
+ return "dependencies" in keySelector && composedKeySelectorSymbol in keySelector;
109
+ }
110
+ function createKeySelectorComposer(baseKeySelectorComposer) {
111
+ return ((...keySelectors) => {
112
+ const resultSelector = baseKeySelectorComposer(...keySelectors);
113
+ resultSelector.dependencies = keySelectors;
114
+ Object.defineProperty(resultSelector, composedKeySelectorSymbol, { value: true });
115
+ return resultSelector;
116
+ });
117
+ }
118
+ //#endregion
119
+ //#region src/_helpers/arePathsEqual.ts
120
+ const arePathsEqual = (path, anotherPath) => {
121
+ if (path.length !== anotherPath.length) return false;
122
+ for (let i = 0; i < path.length; i += 1) if (path[i] !== anotherPath[i]) return false;
123
+ return true;
124
+ };
125
+ //#endregion
126
+ //#region src/keys/defaultKeySelector.ts
127
+ const defaultKeySelector = () => "<DefaultKey>";
128
+ //#endregion
129
+ //#region src/_helpers/isCachedSelector.ts
130
+ const isCachedSelector = (selector) => {
131
+ return selector instanceof Object && "keySelector" in selector && typeof selector.keySelector === "function";
132
+ };
133
+ //#endregion
134
+ //#region src/keys/createKeySelectorCreator.ts
135
+ const areSelectorsEqual = (selector, another) => {
136
+ if (selector === another) return true;
137
+ if (isPropSelector(selector) && isPropSelector(another)) return arePathsEqual(selector.path, another.path);
138
+ return false;
139
+ };
140
+ const flatKeySelectors = (keySelectors) => {
141
+ const result = [];
142
+ for (let i = 0; i < keySelectors.length; i += 1) {
143
+ const keySelector = keySelectors[i];
144
+ if (isComposedKeySelector(keySelector)) result.push(...flatKeySelectors(keySelector.dependencies));
145
+ else result.push(keySelector);
146
+ }
147
+ return result;
148
+ };
149
+ const uniqKeySelectors = (keySelectors) => {
150
+ const result = [];
151
+ for (let i = 0; i < keySelectors.length; i += 1) {
152
+ const keySelector = keySelectors[i];
153
+ if (!result.some((resultKeySelector) => areSelectorsEqual(keySelector, resultKeySelector))) result.push(keySelector);
154
+ }
155
+ return result;
156
+ };
157
+ const excludeDefaultSelectors = (keySelectors) => {
158
+ const result = [];
159
+ for (let i = 0; i < keySelectors.length; i += 1) {
160
+ const keySelector = keySelectors[i];
161
+ if (keySelector !== defaultKeySelector) result.push(keySelector);
162
+ }
163
+ return result;
164
+ };
165
+ function createKeySelectorCreator(keySelectorComposer) {
166
+ return ({ inputSelectors, keySelector }) => {
167
+ let keySelectors = [];
168
+ if (keySelector) keySelectors.push(keySelector);
169
+ inputSelectors.forEach((selector) => {
170
+ if (isCachedSelector(selector)) keySelectors.push(selector.keySelector);
171
+ });
172
+ keySelectors = flatKeySelectors(keySelectors);
173
+ keySelectors = uniqKeySelectors(keySelectors);
174
+ keySelectors = excludeDefaultSelectors(keySelectors);
175
+ if (keySelectors.length === 0) return defaultKeySelector;
176
+ if (keySelectors.length === 1) {
177
+ const [resultSelector] = keySelectors;
178
+ return resultSelector;
179
+ }
180
+ return keySelectorComposer(...keySelectors);
181
+ };
182
+ }
183
+ //#endregion
184
+ //#region src/keys/stringComposeKeySelectors.ts
185
+ const stringComposeKeySelectors = createKeySelectorComposer((...keySelectors) => (state, props) => {
186
+ let key = keySelectors[0](state, props);
187
+ for (let i = 1; i < keySelectors.length; i += 1) {
188
+ key += ":";
189
+ key += keySelectors[i](state, props);
190
+ }
191
+ return key;
192
+ });
193
+ //#endregion
194
+ //#region src/_helpers/temporaryAssign.ts
195
+ const noop = () => void 0;
196
+ function temporaryAssign(target, source) {
197
+ if (typeof target !== "object" || target === null) return {
198
+ result: source,
199
+ rollback: noop
200
+ };
201
+ let temporary = null;
202
+ let deleteProps = null;
203
+ for (const prop in source) if (Object.prototype.hasOwnProperty.call(source, prop)) {
204
+ const targetProp = target[prop];
205
+ const sourceProp = source[prop];
206
+ if (targetProp !== sourceProp) {
207
+ if (Object.prototype.hasOwnProperty.call(target, prop)) {
208
+ if (temporary === null) temporary = {};
209
+ temporary[prop] = targetProp;
210
+ } else {
211
+ if (deleteProps === null) deleteProps = [];
212
+ deleteProps.push(prop);
213
+ }
214
+ target[prop] = sourceProp;
215
+ }
216
+ }
217
+ if (temporary === null && deleteProps === null) return {
218
+ result: target,
219
+ rollback: noop
220
+ };
221
+ const restore = temporary;
222
+ const remove = deleteProps;
223
+ const rollback = () => {
224
+ if (restore !== null) {
225
+ for (const prop in restore) if (Object.prototype.hasOwnProperty.call(restore, prop)) target[prop] = restore[prop];
226
+ }
227
+ if (remove !== null) {
228
+ for (const prop of remove) if (Object.prototype.hasOwnProperty.call(target, prop)) delete target[prop];
229
+ }
230
+ };
231
+ return {
232
+ result: target,
233
+ rollback
234
+ };
235
+ }
236
+ //#endregion
237
+ //#region src/_helpers/getObjectPaths.ts
238
+ const getObjectPaths = (value, parentPath = []) => {
239
+ if (!isObject(value)) return [parentPath];
240
+ return Object.keys(value).reduce((result, key) => {
241
+ const paths = getObjectPaths(value[key], parentPath.concat([key]));
242
+ return result.concat(paths);
243
+ }, []);
244
+ };
245
+ //#endregion
246
+ //#region src/createBoundSelector.ts
247
+ const generateBindingName = (binding) => {
248
+ const structure = Object.keys(binding).reduce((result, key) => ({
249
+ ...result,
250
+ [key]: "[*]"
251
+ }), {});
252
+ return `${Object.keys(structure).join()} -> ${Object.values(structure).join()}`;
253
+ };
254
+ const innerCreateBoundSelector = (baseSelector, binding) => {
255
+ const boundSelector = (state, props) => baseSelector(state, {
256
+ ...props,
257
+ ...binding
258
+ });
259
+ return boundSelector;
260
+ };
261
+ const createBoundInnerSelector = (baseSelector, binding, options = {}) => {
262
+ const bindingStrategy = options.bindingStrategy ?? innerCreateBoundSelector;
263
+ const keySelectorComposer = options.keySelectorComposer ?? stringComposeKeySelectors;
264
+ const boundSelector = bindingStrategy(baseSelector, binding);
265
+ Object.assign(boundSelector, baseSelector);
266
+ boundSelector.dependencies = [baseSelector];
267
+ withDebugName(boundSelector, () => {
268
+ return `${getSelectorName(baseSelector)} (${generateBindingName(binding)})`;
269
+ });
270
+ if (isCachedSelector(baseSelector)) {
271
+ const cachedBoundSelector = boundSelector;
272
+ if (baseSelector.getMatchingSelector) cachedBoundSelector.getMatchingSelector = bindingStrategy(baseSelector.getMatchingSelector, binding);
273
+ if (baseSelector.removeMatchingSelector) cachedBoundSelector.removeMatchingSelector = bindingStrategy(baseSelector.removeMatchingSelector, binding);
274
+ const baseKeySelector = baseSelector.keySelector;
275
+ if (isObject(binding)) {
276
+ const paths = getObjectPaths(binding);
277
+ let keySelectors = isComposedKeySelector(baseKeySelector) ? baseKeySelector.dependencies : [baseKeySelector];
278
+ keySelectors = excludeDefaultSelectors(keySelectors);
279
+ keySelectors = keySelectors.filter((keySelector) => !isPropSelector(keySelector) || !paths.some((path) => arePathsEqual(keySelector.path, path))).map((keySelector) => isPropSelector(keySelector) ? keySelector : bindingStrategy(keySelector, binding));
280
+ if (keySelectors.length === 0) cachedBoundSelector.keySelector = defaultKeySelector;
281
+ else if (keySelectors.length === 1) {
282
+ const [keySelector] = keySelectors;
283
+ cachedBoundSelector.keySelector = keySelector;
284
+ } else cachedBoundSelector.keySelector = keySelectorComposer(...keySelectors);
285
+ } else cachedBoundSelector.keySelector = bindingStrategy(baseKeySelector, binding);
286
+ }
287
+ return boundSelector;
288
+ };
289
+ const createBoundSelector = (baseSelector, binding) => {
290
+ return createBoundInnerSelector(baseSelector, binding, { bindingStrategy: (selector, bindingProps) => {
291
+ const source = bindingProps;
292
+ const keys = Object.keys(source);
293
+ /**
294
+ * Almost every binding is a single key — `bound(selector, { positionId })` —
295
+ * and specialising it removes the two allocations the generic path costs per
296
+ * call: the `{ result, rollback }` object and the `rollback` closure. On a
297
+ * graph with a bound selector per row those are the calls that dominate.
298
+ *
299
+ * The `delete` in the restore stays deliberately. Leaving the key behind as
300
+ * `undefined` would be cheaper — it avoids putting the caller's props object
301
+ * into dictionary mode — but it also changes the object's shape, and
302
+ * `useSelector` memoizes props shallowly: a props object that has grown an
303
+ * extra key never again compares equal to a freshly built one, so the
304
+ * memoization the binding exists to protect would be defeated.
305
+ */
306
+ if (keys.length === 1) {
307
+ const key = keys[0];
308
+ const value = source[key];
309
+ return (state, props) => {
310
+ const target = props;
311
+ if (typeof target !== "object" || target === null) return selector(state, source);
312
+ const previous = target[key];
313
+ if (previous === value) return selector(state, props);
314
+ const had = Object.prototype.hasOwnProperty.call(target, key);
315
+ target[key] = value;
316
+ try {
317
+ return selector(state, props);
318
+ } finally {
319
+ if (had) target[key] = previous;
320
+ else delete target[key];
321
+ }
322
+ };
323
+ }
324
+ return (state, props) => {
325
+ const { result: nextProps, rollback } = temporaryAssign(props, source);
326
+ const result = selector(state, nextProps);
327
+ rollback();
328
+ return result;
329
+ };
330
+ } });
331
+ };
332
+ //#endregion
333
+ //#region src/createEmptySelector.ts
334
+ /**
335
+ * Creates a selector that always resolves to `undefined`. Used as the "no link"
336
+ * branch of a chain (e.g. an optional relation that isn't present).
337
+ *
338
+ * When the base selector is cached, the empty selector is tagged with
339
+ * {@link defaultKeySelector} so that it still passes {@link isCachedSelector}
340
+ * and takes part in key-selector composition. The default key is deliberately
341
+ * the only cache-related metadata copied: an empty selector has no result to
342
+ * memoize, so it needs no `cache` / `getMatchingSelector` of its own, and the
343
+ * default key is dropped by `excludeDefaultSelectors` during composition.
344
+ */
345
+ const createEmptySelector = (baseSelector) => {
346
+ const emptySelector = () => void 0;
347
+ if (isCachedSelector(baseSelector)) emptySelector.keySelector = defaultKeySelector;
348
+ return emptySelector;
349
+ };
350
+ //#endregion
351
+ //#region src/createAdaptedSelector.ts
352
+ const generateMappingName = (mapping) => {
353
+ if (mapping.name) return mapping.name;
354
+ const structure = mapping(new Proxy({}, { get: (_target, key) => key }));
355
+ return `${Object.keys(structure).join()} -> ${Object.values(structure).join()}`;
356
+ };
357
+ const innerCreateAdaptedSelector = (baseSelector, mapping) => (state, props) => {
358
+ return baseSelector(state, mapping(props));
359
+ };
360
+ const createAdaptedSelector = (baseSelector, mapping) => {
361
+ const adaptedSelector = innerCreateAdaptedSelector(baseSelector, mapping);
362
+ Object.assign(adaptedSelector, baseSelector);
363
+ adaptedSelector.dependencies = [baseSelector];
364
+ withDebugName(adaptedSelector, () => {
365
+ return `${getSelectorName(baseSelector)} (${generateMappingName(mapping)})`;
366
+ });
367
+ if (isCachedSelector(baseSelector)) {
368
+ const cachedAdaptedSelector = adaptedSelector;
369
+ if (baseSelector.getMatchingSelector) cachedAdaptedSelector.getMatchingSelector = innerCreateAdaptedSelector(baseSelector.getMatchingSelector, mapping);
370
+ if (baseSelector.removeMatchingSelector) cachedAdaptedSelector.removeMatchingSelector = innerCreateAdaptedSelector(baseSelector.removeMatchingSelector, mapping);
371
+ cachedAdaptedSelector.keySelector = innerCreateAdaptedSelector(baseSelector.keySelector, mapping);
372
+ }
373
+ return adaptedSelector;
374
+ };
375
+ //#endregion
376
+ //#region src/_helpers/stringifyFunction.ts
377
+ const stringifyFunction = (source) => {
378
+ return String(source).replace(/\s+/g, " ").trim();
379
+ };
380
+ //#endregion
381
+ //#region src/_helpers/generateSelectorKey.ts
382
+ const generateSelectorKey = (selector) => {
383
+ const dependencies = selector.dependencies ?? [];
384
+ let result = stringifyFunction(selector);
385
+ for (let i = dependencies.length - 1; i >= 0; i -= 1) {
386
+ const dependency = dependencies[i];
387
+ result += stringifyFunction(dependency);
388
+ }
389
+ return result;
390
+ };
391
+ //#endregion
392
+ //#region src/createChainSelector.ts
393
+ function createChainSelector(selector, options, prevChain) {
394
+ const chain = (fn, chainOptions) => {
395
+ const combinedOptions = {
396
+ ...options,
397
+ ...chainOptions
398
+ };
399
+ const keySelector = isCachedSelector(selector) ? selector.keySelector : defaultKeySelector;
400
+ const { createSelectorOptions = () => ({}), keySelectorComposer = stringComposeKeySelectors } = combinedOptions;
401
+ const keySelectorCreator = createKeySelectorCreator(keySelectorComposer);
402
+ const higherOrderSelector = (0, _veksa_re_reselect.createCachedSelector)([selector], fn)({
403
+ ...createSelectorOptions(),
404
+ keySelector
405
+ });
406
+ withDebugName(higherOrderSelector, () => {
407
+ return `higher order for ${getSelectorName(selector)} (${stringifyFunction(fn)})`;
408
+ });
409
+ const combinedSelector = (state, props) => {
410
+ const derivedSelector = higherOrderSelector(state, props);
411
+ runInDebug(() => {
412
+ combinedSelector.dependencies = [higherOrderSelector, derivedSelector];
413
+ if (!getSelectorName(derivedSelector)) defineDynamicSelectorName(derivedSelector, () => {
414
+ return `derived from ${getSelectorName(selector)} (${generateSelectorKey(derivedSelector)})`;
415
+ });
416
+ defineDynamicSelectorName(combinedSelector, () => {
417
+ return `${getSelectorName(selector)} (chained by ${getSelectorName(derivedSelector)})`;
418
+ });
419
+ });
420
+ return derivedSelector(state, props);
421
+ };
422
+ combinedSelector.dependencies = [higherOrderSelector];
423
+ combinedSelector.cache = higherOrderSelector.cache;
424
+ /**
425
+ * The derived selector's key selector, memoized on the derived selector itself.
426
+ *
427
+ * This used to be a second `createCachedSelector` over `[higherOrderSelector]`,
428
+ * which meant every key computation paid a whole extra cached-selector layer —
429
+ * its own key computation, its own cache lookup, and its own evaluation of
430
+ * `higherOrderSelector` — to produce a value that depends on nothing but the
431
+ * derived selector. A `WeakMap` keyed on that selector is the same mapping with
432
+ * none of the layer, and it shares across cache keys rather than per key.
433
+ *
434
+ * Note what is deliberately *not* memoized: the `(state, props)` pair. `props`
435
+ * is mutated in place by `createBoundSelector`, so two calls can pass the same
436
+ * object reference with different contents, and a reference-keyed cache would
437
+ * hand back a stale selector.
438
+ */
439
+ const derivedKeySelectors = /* @__PURE__ */ new WeakMap();
440
+ combinedSelector.keySelector = (state, props) => {
441
+ const derivedSelector = higherOrderSelector(state, props);
442
+ let derivedKeySelector = derivedKeySelectors.get(derivedSelector);
443
+ if (derivedKeySelector === void 0) {
444
+ derivedKeySelector = keySelectorCreator({ inputSelectors: [higherOrderSelector, derivedSelector] });
445
+ derivedKeySelectors.set(derivedSelector, derivedKeySelector);
446
+ }
447
+ return derivedKeySelector(state, props);
448
+ };
449
+ withDebugName(combinedSelector, () => {
450
+ return `${getSelectorName(selector)} (will be chained ${stringifyFunction(fn)})`;
451
+ });
452
+ return createChainSelector(combinedSelector, combinedOptions, Object.assign(fn, { parentChain: prevChain }));
453
+ };
454
+ const map = (fn, mapOptions) => {
455
+ const mapSelector = (result) => {
456
+ const output = fn(result);
457
+ const mapSelector = () => output;
458
+ withDebugName(mapSelector, () => {
459
+ return `mapped from ${getSelectorName(selector)} (${stringifyFunction(fn)})`;
460
+ });
461
+ return mapSelector;
462
+ };
463
+ return chain(mapSelector, mapOptions);
464
+ };
465
+ const build = () => {
466
+ return Object.assign(selector, { chainHierarchy: prevChain });
467
+ };
468
+ return {
469
+ chain,
470
+ map,
471
+ build
472
+ };
473
+ }
474
+ //#endregion
475
+ //#region src/createSequenceSelector.ts
476
+ function createSequenceSelector(selectors, selectorCreator = _veksa_reselect.createSelector) {
477
+ return selectorCreator(selectors, (...results) => results);
478
+ }
479
+ //#endregion
480
+ //#region src/createCachedSequenceSelector.ts
481
+ function createCachedSequenceSelector(selectors) {
482
+ return createSequenceSelector(selectors, _veksa_re_reselect.createCachedSelector);
483
+ }
484
+ //#endregion
485
+ //#region src/createStructuredSelector.ts
486
+ const createStructuredSelector = _veksa_reselect.createStructuredSelector;
487
+ //#endregion
488
+ //#region src/createCachedStructuredSelector.ts
489
+ function createCachedStructuredSelector(selectors) {
490
+ return createStructuredSelector(selectors, _veksa_re_reselect.createCachedSelector);
491
+ }
492
+ //#endregion
493
+ //#region src/keys/arrayComposeKeySelectors.ts
494
+ const arrayComposeKeySelectors = createKeySelectorComposer((...keySelectors) => (state, props) => {
495
+ let keyPath = [];
496
+ for (let i = 0; i < keySelectors.length; i += 1) {
497
+ const key = keySelectors[i](state, props);
498
+ if (Array.isArray(key)) keyPath = keyPath.concat(key);
499
+ else keyPath.push(key);
500
+ }
501
+ return keyPath;
502
+ });
503
+ //#endregion
504
+ //#region src/cache/intervalMapCache.ts
505
+ /**
506
+ * Buckets used to live in a module-level `Record<string, …>` keyed by an
507
+ * incrementing numeric id, which meant every `get` and `set` coerced that number to
508
+ * a string and re-read the global record — four times per cache hit in `get`.
509
+ * Holding the entries on the instance removes both, and a `Map` keeps non-string
510
+ * keys as they are instead of stringifying them.
511
+ */
512
+ const buckets = /* @__PURE__ */ new Set();
513
+ const cacheLifetime = 1e4;
514
+ let garbageCollectorStarted = false;
515
+ const runGarbageCollector = () => {
516
+ const currentTime = Date.now();
517
+ buckets.forEach((bucket) => {
518
+ if (bucket.sweep(currentTime)) buckets.delete(bucket);
519
+ });
520
+ window.setTimeout(runGarbageCollector, cacheLifetime);
521
+ };
522
+ const initGarbageCollector = () => {
523
+ if (garbageCollectorStarted) return;
524
+ if (typeof window !== "undefined") {
525
+ garbageCollectorStarted = true;
526
+ window.setTimeout(runGarbageCollector, cacheLifetime);
527
+ }
528
+ };
529
+ var IntervalMapCache = class {
530
+ constructor() {
531
+ this.entries = /* @__PURE__ */ new Map();
532
+ }
533
+ set(key, data) {
534
+ const entry = this.entries.get(key);
535
+ if (entry === void 0) {
536
+ buckets.add(this);
537
+ this.entries.set(key, {
538
+ data,
539
+ time: Date.now()
540
+ });
541
+ } else {
542
+ entry.data = data;
543
+ entry.time = Date.now();
544
+ }
545
+ }
546
+ get(key) {
547
+ const entry = this.entries.get(key);
548
+ if (entry === void 0) return;
549
+ entry.time = Date.now();
550
+ return entry.data;
551
+ }
552
+ remove(key) {
553
+ this.entries.delete(key);
554
+ }
555
+ clear() {
556
+ this.entries.clear();
557
+ buckets.delete(this);
558
+ }
559
+ /**
560
+ * Drops entries untouched for longer than the lifetime. Returns whether the
561
+ * bucket is now empty, which is what lets the collector unregister it.
562
+ */
563
+ sweep(currentTime) {
564
+ this.entries.forEach((entry, key) => {
565
+ if (currentTime - entry.time > cacheLifetime) this.entries.delete(key);
566
+ });
567
+ return this.entries.size === 0;
568
+ }
569
+ };
570
+ //#endregion
571
+ //#region src/cache/TreeCache.ts
572
+ const normalizeKey = (key) => Array.isArray(key) ? key : [key];
573
+ var TreeCacheNode = class {};
574
+ var TreeCache = class {
575
+ constructor(options) {
576
+ this.cacheObjectCreator = options.cacheObjectCreator ?? (() => new _veksa_re_reselect.FlatObjectCache());
577
+ const root = new TreeCacheNode();
578
+ root.cache = this.cacheObjectCreator();
579
+ this.root = root;
580
+ }
581
+ clear() {
582
+ const root = new TreeCacheNode();
583
+ root.cache = this.cacheObjectCreator();
584
+ this.root = root;
585
+ }
586
+ get(key) {
587
+ if (!Array.isArray(key)) {
588
+ const cacheResponse = this.root.cache?.get(key);
589
+ return cacheResponse instanceof TreeCacheNode ? cacheResponse.selectorFn : void 0;
590
+ }
591
+ let currentNode = this.root;
592
+ for (let i = 0; i < key.length; i += 1) {
593
+ const item = key[i];
594
+ const cacheResponse = currentNode.cache?.get(item);
595
+ if (cacheResponse instanceof TreeCacheNode) currentNode = cacheResponse;
596
+ else return;
597
+ }
598
+ return currentNode.selectorFn;
599
+ }
600
+ set(key, selectorFn) {
601
+ const keyPath = normalizeKey(key);
602
+ let currentNode = this.root;
603
+ for (let i = 0; i < keyPath.length; i += 1) {
604
+ const item = keyPath[i];
605
+ if (!currentNode.cache) currentNode.cache = this.cacheObjectCreator();
606
+ const cacheResponse = currentNode.cache.get(item);
607
+ if (cacheResponse instanceof TreeCacheNode) currentNode = cacheResponse;
608
+ else {
609
+ const node = new TreeCacheNode();
610
+ currentNode.cache.set(item, node);
611
+ currentNode = node;
612
+ }
613
+ }
614
+ currentNode.selectorFn = selectorFn;
615
+ }
616
+ remove(key) {
617
+ const keyPath = normalizeKey(key);
618
+ let currentNode = this.root;
619
+ for (let i = 0; i < keyPath.length; i += 1) {
620
+ const item = keyPath[i];
621
+ const cacheResponse = currentNode.cache?.get(item);
622
+ if (cacheResponse instanceof TreeCacheNode) currentNode = cacheResponse;
623
+ else return;
624
+ }
625
+ currentNode.selectorFn = void 0;
626
+ }
627
+ /**
628
+ * Called by re-reselect on every cache operation, so neither the wrapping array
629
+ * nor the `every` callback is allocated here.
630
+ */
631
+ isValidCacheKey(key) {
632
+ const rootCache = this.root.cache;
633
+ if (rootCache?.isValidCacheKey === void 0) return true;
634
+ if (!Array.isArray(key)) return rootCache.isValidCacheKey(key);
635
+ for (let i = 0; i < key.length; i += 1) if (!rootCache.isValidCacheKey(key[i])) return false;
636
+ return true;
637
+ }
638
+ };
639
+ //#endregion
640
+ //#region src/_hooks/useMemoWith.ts
641
+ const useMemoWith = (value, comparator) => {
642
+ const ref = (0, react.useRef)(value);
643
+ if (!comparator(value, ref.current)) ref.current = value;
644
+ return ref.current;
645
+ };
646
+ //#endregion
647
+ //#region src/_hooks/useSelector.ts
648
+ function useSelector(selector, ...params) {
649
+ const props = params[0];
650
+ const memoizedProps = useMemoWith(props, _veksa_react_redux.shallowEqual);
651
+ const unfrozenProps = (0, react.useMemo)(() => {
652
+ return Object.isFrozen(memoizedProps) ? { ...memoizedProps } : memoizedProps;
653
+ }, [memoizedProps]);
654
+ return (0, _veksa_react_redux.useSelector)((0, react.useCallback)((state) => {
655
+ return selector(state, unfrozenProps);
656
+ }, [selector, unfrozenProps]), { devModeChecks: {
657
+ stabilityCheck: "never",
658
+ identityFunctionCheck: "never"
659
+ } });
660
+ }
661
+ //#endregion
662
+ exports.IntervalMapCache = IntervalMapCache;
663
+ exports.TreeCache = TreeCache;
664
+ exports.arrayComposeKeySelectors = arrayComposeKeySelectors;
665
+ exports.createAdaptedSelector = createAdaptedSelector;
666
+ exports.createBoundSelector = createBoundSelector;
667
+ exports.createCachedSequenceSelector = createCachedSequenceSelector;
668
+ exports.createCachedStructuredSelector = createCachedStructuredSelector;
669
+ exports.createChainSelector = createChainSelector;
670
+ exports.createEmptySelector = createEmptySelector;
671
+ exports.createKeySelectorComposer = createKeySelectorComposer;
672
+ exports.createKeySelectorCreator = createKeySelectorCreator;
673
+ exports.createPathSelector = createPathSelector;
674
+ exports.createPropSelector = createPropSelector;
675
+ exports.createSegmentSelector = createSegmentSelector;
676
+ exports.defaultKeySelector = defaultKeySelector;
677
+ exports.initGarbageCollector = initGarbageCollector;
678
+ exports.isDebugMode = isDebugMode;
679
+ exports.setDebugMode = setDebugMode;
680
+ exports.stringComposeKeySelectors = stringComposeKeySelectors;
681
+ exports.useSelector = useSelector;
682
+
683
+ //# sourceMappingURL=reselectKit.development.cjs.map