@signaltree/core 4.0.15 → 4.1.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 (109) hide show
  1. package/README.md +106 -38
  2. package/dist/constants.js +6 -0
  3. package/dist/deep-clone.js +80 -0
  4. package/dist/deep-equal.js +41 -0
  5. package/dist/enhancers/batching/lib/batching.js +141 -135
  6. package/dist/enhancers/computed/lib/computed.js +18 -16
  7. package/dist/enhancers/devtools/lib/devtools.js +303 -260
  8. package/dist/enhancers/entities/lib/entities.js +109 -104
  9. package/dist/enhancers/index.js +65 -77
  10. package/dist/enhancers/memoization/lib/memoization.js +339 -351
  11. package/dist/enhancers/middleware/lib/async-helpers.js +71 -79
  12. package/dist/enhancers/middleware/lib/middleware.js +126 -169
  13. package/dist/enhancers/presets/lib/presets.js +82 -71
  14. package/dist/enhancers/serialization/constants.js +14 -13
  15. package/dist/enhancers/serialization/lib/serialization.js +615 -623
  16. package/dist/enhancers/time-travel/lib/time-travel.js +178 -177
  17. package/dist/index.d.ts +1 -17
  18. package/dist/index.js +19 -16
  19. package/dist/is-built-in-object.js +23 -0
  20. package/dist/lib/constants.js +51 -55
  21. package/dist/lib/memory/memory-manager.js +152 -154
  22. package/dist/lib/performance/diff-engine.js +141 -141
  23. package/dist/lib/performance/path-index.js +139 -137
  24. package/dist/lib/performance/update-engine.js +171 -176
  25. package/dist/lib/security/security-validator.js +110 -128
  26. package/dist/lib/signal-tree.js +577 -611
  27. package/dist/lib/types.js +3 -9
  28. package/dist/lib/utils.js +236 -268
  29. package/dist/lru-cache.js +64 -0
  30. package/dist/parse-path.js +13 -0
  31. package/package.json +30 -16
  32. package/src/index.d.ts +17 -0
  33. package/{dist → src}/lib/utils.d.ts +1 -0
  34. package/dist/enhancers/batching/index.js +0 -1
  35. package/dist/enhancers/batching/jest.config.js +0 -21
  36. package/dist/enhancers/batching/test-setup.js +0 -5
  37. package/dist/enhancers/computed/index.js +0 -1
  38. package/dist/enhancers/computed/jest.config.js +0 -21
  39. package/dist/enhancers/devtools/index.js +0 -1
  40. package/dist/enhancers/devtools/jest.config.js +0 -21
  41. package/dist/enhancers/devtools/test-setup.js +0 -5
  42. package/dist/enhancers/entities/index.js +0 -1
  43. package/dist/enhancers/entities/jest.config.js +0 -21
  44. package/dist/enhancers/entities/test-setup.js +0 -5
  45. package/dist/enhancers/memoization/index.js +0 -1
  46. package/dist/enhancers/memoization/jest.config.js +0 -21
  47. package/dist/enhancers/memoization/test-setup.js +0 -5
  48. package/dist/enhancers/middleware/index.js +0 -2
  49. package/dist/enhancers/middleware/jest.config.js +0 -21
  50. package/dist/enhancers/middleware/test-setup.js +0 -5
  51. package/dist/enhancers/presets/index.js +0 -1
  52. package/dist/enhancers/presets/jest.config.js +0 -21
  53. package/dist/enhancers/presets/test-setup.js +0 -5
  54. package/dist/enhancers/serialization/index.js +0 -2
  55. package/dist/enhancers/serialization/jest.config.js +0 -21
  56. package/dist/enhancers/serialization/test-setup.js +0 -5
  57. package/dist/enhancers/time-travel/index.js +0 -1
  58. package/dist/enhancers/time-travel/jest.config.js +0 -21
  59. package/dist/enhancers/time-travel/lib/utils.js +0 -1
  60. package/dist/enhancers/time-travel/test-setup.js +0 -5
  61. package/dist/enhancers/types.js +0 -0
  62. /package/{dist → src}/enhancers/batching/index.d.ts +0 -0
  63. /package/{dist → src}/enhancers/batching/jest.config.d.ts +0 -0
  64. /package/{dist → src}/enhancers/batching/lib/batching.d.ts +0 -0
  65. /package/{dist → src}/enhancers/batching/test-setup.d.ts +0 -0
  66. /package/{dist → src}/enhancers/computed/index.d.ts +0 -0
  67. /package/{dist → src}/enhancers/computed/jest.config.d.ts +0 -0
  68. /package/{dist → src}/enhancers/computed/lib/computed.d.ts +0 -0
  69. /package/{dist → src}/enhancers/devtools/index.d.ts +0 -0
  70. /package/{dist → src}/enhancers/devtools/jest.config.d.ts +0 -0
  71. /package/{dist → src}/enhancers/devtools/lib/devtools.d.ts +0 -0
  72. /package/{dist → src}/enhancers/devtools/test-setup.d.ts +0 -0
  73. /package/{dist → src}/enhancers/entities/index.d.ts +0 -0
  74. /package/{dist → src}/enhancers/entities/jest.config.d.ts +0 -0
  75. /package/{dist → src}/enhancers/entities/lib/entities.d.ts +0 -0
  76. /package/{dist → src}/enhancers/entities/test-setup.d.ts +0 -0
  77. /package/{dist → src}/enhancers/index.d.ts +0 -0
  78. /package/{dist → src}/enhancers/memoization/index.d.ts +0 -0
  79. /package/{dist → src}/enhancers/memoization/jest.config.d.ts +0 -0
  80. /package/{dist → src}/enhancers/memoization/lib/memoization.d.ts +0 -0
  81. /package/{dist → src}/enhancers/memoization/test-setup.d.ts +0 -0
  82. /package/{dist → src}/enhancers/middleware/index.d.ts +0 -0
  83. /package/{dist → src}/enhancers/middleware/jest.config.d.ts +0 -0
  84. /package/{dist → src}/enhancers/middleware/lib/async-helpers.d.ts +0 -0
  85. /package/{dist → src}/enhancers/middleware/lib/middleware.d.ts +0 -0
  86. /package/{dist → src}/enhancers/middleware/test-setup.d.ts +0 -0
  87. /package/{dist → src}/enhancers/presets/index.d.ts +0 -0
  88. /package/{dist → src}/enhancers/presets/jest.config.d.ts +0 -0
  89. /package/{dist → src}/enhancers/presets/lib/presets.d.ts +0 -0
  90. /package/{dist → src}/enhancers/presets/test-setup.d.ts +0 -0
  91. /package/{dist → src}/enhancers/serialization/constants.d.ts +0 -0
  92. /package/{dist → src}/enhancers/serialization/index.d.ts +0 -0
  93. /package/{dist → src}/enhancers/serialization/jest.config.d.ts +0 -0
  94. /package/{dist → src}/enhancers/serialization/lib/serialization.d.ts +0 -0
  95. /package/{dist → src}/enhancers/serialization/test-setup.d.ts +0 -0
  96. /package/{dist → src}/enhancers/time-travel/index.d.ts +0 -0
  97. /package/{dist → src}/enhancers/time-travel/jest.config.d.ts +0 -0
  98. /package/{dist → src}/enhancers/time-travel/lib/time-travel.d.ts +0 -0
  99. /package/{dist → src}/enhancers/time-travel/lib/utils.d.ts +0 -0
  100. /package/{dist → src}/enhancers/time-travel/test-setup.d.ts +0 -0
  101. /package/{dist → src}/enhancers/types.d.ts +0 -0
  102. /package/{dist → src}/lib/constants.d.ts +0 -0
  103. /package/{dist → src}/lib/memory/memory-manager.d.ts +0 -0
  104. /package/{dist → src}/lib/performance/diff-engine.d.ts +0 -0
  105. /package/{dist → src}/lib/performance/path-index.d.ts +0 -0
  106. /package/{dist → src}/lib/performance/update-engine.d.ts +0 -0
  107. /package/{dist → src}/lib/security/security-validator.d.ts +0 -0
  108. /package/{dist → src}/lib/signal-tree.d.ts +0 -0
  109. /package/{dist → src}/lib/types.d.ts +0 -0
@@ -1,110 +1,115 @@
1
1
  import { computed } from '@angular/core';
2
- import { isAnySignal, isNodeAccessor } from '../../../lib/utils';
2
+ import { isAnySignal, isNodeAccessor } from '../../../lib/utils.js';
3
+
3
4
  function createEntityHelpers(tree, entityKey) {
4
- const getEntitySignal = () => {
5
- const stateProperty = tree.state[entityKey];
6
- if (!stateProperty) {
7
- throw new Error(`Entity key '${String(entityKey)}' does not exist in the state`);
8
- }
9
- if (!isAnySignal(stateProperty)) {
10
- throw new Error(`Entity key '${String(entityKey)}' is not a signal. This should not happen with SignalTree.`);
11
- }
12
- const signal = stateProperty;
13
- const value = signal();
14
- if (!Array.isArray(value)) {
15
- throw new Error(`Entity key '${String(entityKey)}' does not contain an array. Current type: ${typeof value}`);
16
- }
17
- return signal;
18
- };
19
- const setSignalValue = (signal, value) => {
20
- if (isNodeAccessor(signal)) {
21
- signal(value);
22
- }
23
- else {
24
- signal.set(value);
25
- }
26
- };
27
- return {
28
- add: (entity) => {
29
- const entitySignal = getEntitySignal();
30
- const currentEntities = entitySignal();
31
- if (currentEntities.some((e) => e.id === entity.id)) {
32
- throw new Error(`Entity with id '${entity.id}' already exists`);
33
- }
34
- setSignalValue(entitySignal, [...currentEntities, entity]);
35
- },
36
- update: (id, updates) => {
37
- const entitySignal = getEntitySignal();
38
- const currentEntities = entitySignal();
39
- const updatedEntities = currentEntities.map((entity) => entity.id === id ? { ...entity, ...updates } : entity);
40
- setSignalValue(entitySignal, updatedEntities);
41
- },
42
- remove: (id) => {
43
- const entitySignal = getEntitySignal();
44
- const currentEntities = entitySignal();
45
- const filteredEntities = currentEntities.filter((entity) => entity.id !== id);
46
- setSignalValue(entitySignal, filteredEntities);
47
- },
48
- upsert: (entity) => {
49
- const entitySignal = getEntitySignal();
50
- const currentEntities = entitySignal();
51
- const index = currentEntities.findIndex((e) => e.id === entity.id);
52
- if (index >= 0) {
53
- const updatedEntities = [...currentEntities];
54
- updatedEntities[index] = entity;
55
- setSignalValue(entitySignal, updatedEntities);
56
- }
57
- else {
58
- setSignalValue(entitySignal, [...currentEntities, entity]);
59
- }
60
- },
61
- selectById: (id) => {
62
- const entitySignal = getEntitySignal();
63
- return computed(() => entitySignal().find((entity) => entity.id === id));
64
- },
65
- selectBy: (predicate) => {
66
- const entitySignal = getEntitySignal();
67
- return computed(() => entitySignal().filter(predicate));
68
- },
69
- selectIds: () => {
70
- const entitySignal = getEntitySignal();
71
- return computed(() => entitySignal().map((entity) => entity.id));
72
- },
73
- selectAll: () => {
74
- const entitySignal = getEntitySignal();
75
- return entitySignal;
76
- },
77
- selectTotal: () => {
78
- const entitySignal = getEntitySignal();
79
- return computed(() => entitySignal().length);
80
- },
81
- clear: () => {
82
- const entitySignal = getEntitySignal();
83
- setSignalValue(entitySignal, []);
84
- },
85
- };
5
+ const getEntitySignal = () => {
6
+ const stateProperty = tree.state[entityKey];
7
+ if (!stateProperty) {
8
+ throw new Error(`Entity key '${String(entityKey)}' does not exist in the state`);
9
+ }
10
+ if (!isAnySignal(stateProperty)) {
11
+ throw new Error(`Entity key '${String(entityKey)}' is not a signal. This should not happen with SignalTree.`);
12
+ }
13
+ const signal = stateProperty;
14
+ const value = signal();
15
+ if (!Array.isArray(value)) {
16
+ throw new Error(`Entity key '${String(entityKey)}' does not contain an array. Current type: ${typeof value}`);
17
+ }
18
+ return signal;
19
+ };
20
+ const setSignalValue = (signal, value) => {
21
+ if (isNodeAccessor(signal)) {
22
+ signal(value);
23
+ } else {
24
+ signal.set(value);
25
+ }
26
+ };
27
+ return {
28
+ add: entity => {
29
+ const entitySignal = getEntitySignal();
30
+ const currentEntities = entitySignal();
31
+ if (currentEntities.some(e => e.id === entity.id)) {
32
+ throw new Error(`Entity with id '${entity.id}' already exists`);
33
+ }
34
+ setSignalValue(entitySignal, [...currentEntities, entity]);
35
+ },
36
+ update: (id, updates) => {
37
+ const entitySignal = getEntitySignal();
38
+ const currentEntities = entitySignal();
39
+ const updatedEntities = currentEntities.map(entity => entity.id === id ? {
40
+ ...entity,
41
+ ...updates
42
+ } : entity);
43
+ setSignalValue(entitySignal, updatedEntities);
44
+ },
45
+ remove: id => {
46
+ const entitySignal = getEntitySignal();
47
+ const currentEntities = entitySignal();
48
+ const filteredEntities = currentEntities.filter(entity => entity.id !== id);
49
+ setSignalValue(entitySignal, filteredEntities);
50
+ },
51
+ upsert: entity => {
52
+ const entitySignal = getEntitySignal();
53
+ const currentEntities = entitySignal();
54
+ const index = currentEntities.findIndex(e => e.id === entity.id);
55
+ if (index >= 0) {
56
+ const updatedEntities = [...currentEntities];
57
+ updatedEntities[index] = entity;
58
+ setSignalValue(entitySignal, updatedEntities);
59
+ } else {
60
+ setSignalValue(entitySignal, [...currentEntities, entity]);
61
+ }
62
+ },
63
+ selectById: id => {
64
+ const entitySignal = getEntitySignal();
65
+ return computed(() => entitySignal().find(entity => entity.id === id));
66
+ },
67
+ selectBy: predicate => {
68
+ const entitySignal = getEntitySignal();
69
+ return computed(() => entitySignal().filter(predicate));
70
+ },
71
+ selectIds: () => {
72
+ const entitySignal = getEntitySignal();
73
+ return computed(() => entitySignal().map(entity => entity.id));
74
+ },
75
+ selectAll: () => {
76
+ const entitySignal = getEntitySignal();
77
+ return entitySignal;
78
+ },
79
+ selectTotal: () => {
80
+ const entitySignal = getEntitySignal();
81
+ return computed(() => entitySignal().length);
82
+ },
83
+ clear: () => {
84
+ const entitySignal = getEntitySignal();
85
+ setSignalValue(entitySignal, []);
86
+ }
87
+ };
86
88
  }
87
- export function withEntities(config = {}) {
88
- const { enabled = true } = config;
89
- return function enhanceWithEntities(tree) {
90
- if (!enabled) {
91
- return tree;
92
- }
93
- const enhancedTree = Object.assign(tree, {
94
- entities(entityKey) {
95
- return createEntityHelpers(tree, entityKey);
96
- },
97
- });
98
- return enhancedTree;
99
- };
89
+ function withEntities(config = {}) {
90
+ const {
91
+ enabled = true
92
+ } = config;
93
+ return function enhanceWithEntities(tree) {
94
+ if (!enabled) {
95
+ return tree;
96
+ }
97
+ const enhancedTree = Object.assign(tree, {
98
+ entities(entityKey) {
99
+ return createEntityHelpers(tree, entityKey);
100
+ }
101
+ });
102
+ return enhancedTree;
103
+ };
100
104
  }
101
- export function enableEntities() {
102
- return withEntities({ enabled: true });
105
+ function enableEntities() {
106
+ return withEntities({
107
+ enabled: true
108
+ });
103
109
  }
104
- export function withHighPerformanceEntities() {
105
- return withEntities({
106
- enabled: true,
107
- trackChanges: true,
108
- validateIds: true,
109
- });
110
+ function withHighPerformanceEntities() {
111
+ return withEntities({
112
+ enabled: true});
110
113
  }
114
+
115
+ export { enableEntities, withEntities, withHighPerformanceEntities };
@@ -1,84 +1,72 @@
1
- import { SIGNAL_TREE_MESSAGES } from '../lib/constants';
2
- import { ENHANCER_META } from '../lib/types';
3
- export function createEnhancer(meta, enhancerFn) {
4
- const fn = enhancerFn;
1
+ import { SIGNAL_TREE_MESSAGES } from '../lib/constants.js';
2
+ import { ENHANCER_META } from '../lib/types.js';
3
+
4
+ function createEnhancer(meta, enhancerFn) {
5
+ const fn = enhancerFn;
6
+ try {
7
+ fn.metadata = meta;
5
8
  try {
6
- fn.metadata = meta;
7
- try {
8
- fn[ENHANCER_META] = meta;
9
- }
10
- catch {
11
- }
12
- }
13
- catch {
14
- }
15
- return fn;
9
+ fn[ENHANCER_META] = meta;
10
+ } catch {}
11
+ } catch {}
12
+ return fn;
16
13
  }
17
- export function resolveEnhancerOrder(enhancers, availableCapabilities = new Set(), debugMode = false) {
18
- const nodes = enhancers.map((e, idx) => ({
19
- fn: e,
20
- name: e.metadata && e.metadata.name
21
- ? String(e.metadata.name)
22
- : `enhancer#${idx}`,
23
- requires: new Set(e.metadata?.requires ?? []),
24
- provides: new Set(e.metadata?.provides ?? []),
25
- }));
26
- const adj = new Map();
27
- const nameToNode = new Map();
28
- for (const n of nodes) {
29
- nameToNode.set(n.name, n);
30
- adj.set(n.name, new Set());
31
- }
32
- for (const a of nodes) {
33
- for (const b of nodes) {
34
- if (a === b)
35
- continue;
36
- for (const req of b.requires) {
37
- if (availableCapabilities.has(req))
38
- continue;
39
- if (a.provides.has(req)) {
40
- const set = adj.get(a.name);
41
- if (set)
42
- set.add(b.name);
43
- }
44
- }
14
+ function resolveEnhancerOrder(enhancers, availableCapabilities = new Set(), debugMode = false) {
15
+ const nodes = enhancers.map((e, idx) => ({
16
+ fn: e,
17
+ name: e.metadata && e.metadata.name ? String(e.metadata.name) : `enhancer#${idx}`,
18
+ requires: new Set(e.metadata?.requires ?? []),
19
+ provides: new Set(e.metadata?.provides ?? [])
20
+ }));
21
+ const adj = new Map();
22
+ const nameToNode = new Map();
23
+ for (const n of nodes) {
24
+ nameToNode.set(n.name, n);
25
+ adj.set(n.name, new Set());
26
+ }
27
+ for (const a of nodes) {
28
+ for (const b of nodes) {
29
+ if (a === b) continue;
30
+ for (const req of b.requires) {
31
+ if (availableCapabilities.has(req)) continue;
32
+ if (a.provides.has(req)) {
33
+ const set = adj.get(a.name);
34
+ if (set) set.add(b.name);
45
35
  }
36
+ }
46
37
  }
47
- const inDegree = new Map();
48
- for (const entry of adj.keys())
49
- inDegree.set(entry, 0);
50
- for (const [, outs] of adj) {
51
- for (const to of outs)
52
- inDegree.set(to, (inDegree.get(to) || 0) + 1);
38
+ }
39
+ const inDegree = new Map();
40
+ for (const entry of adj.keys()) inDegree.set(entry, 0);
41
+ for (const [, outs] of adj) {
42
+ for (const to of outs) inDegree.set(to, (inDegree.get(to) || 0) + 1);
43
+ }
44
+ const queue = [];
45
+ for (const [name, deg] of inDegree.entries()) {
46
+ if (deg === 0) queue.push(name);
47
+ }
48
+ const ordered = [];
49
+ while (queue.length > 0) {
50
+ const n = queue.shift();
51
+ if (!n) break;
52
+ ordered.push(n);
53
+ const outs = adj.get(n);
54
+ if (!outs) continue;
55
+ for (const m of outs) {
56
+ inDegree.set(m, (inDegree.get(m) || 0) - 1);
57
+ if (inDegree.get(m) === 0) queue.push(m);
53
58
  }
54
- const queue = [];
55
- for (const [name, deg] of inDegree.entries()) {
56
- if (deg === 0)
57
- queue.push(name);
58
- }
59
- const ordered = [];
60
- while (queue.length > 0) {
61
- const n = queue.shift();
62
- if (!n)
63
- break;
64
- ordered.push(n);
65
- const outs = adj.get(n);
66
- if (!outs)
67
- continue;
68
- for (const m of outs) {
69
- inDegree.set(m, (inDegree.get(m) || 0) - 1);
70
- if (inDegree.get(m) === 0)
71
- queue.push(m);
72
- }
73
- }
74
- if (ordered.length !== nodes.length) {
75
- if (debugMode) {
76
- console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_CYCLE_DETECTED);
77
- }
78
- return enhancers;
59
+ }
60
+ if (ordered.length !== nodes.length) {
61
+ if (debugMode) {
62
+ console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_CYCLE_DETECTED);
79
63
  }
80
- return ordered.map((name) => {
81
- const n = nameToNode.get(name);
82
- return (n ? n.fn : enhancers[0]);
83
- });
64
+ return enhancers;
65
+ }
66
+ return ordered.map(name => {
67
+ const n = nameToNode.get(name);
68
+ return n ? n.fn : enhancers[0];
69
+ });
84
70
  }
71
+
72
+ export { createEnhancer, resolveEnhancerOrder };