@dxos/app-graph 0.8.3 → 0.8.4-main.03d5cd7b56
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.
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
- package/dist/lib/neutral/chunk-WJJ5KEOH.mjs +1477 -0
- package/dist/lib/neutral/chunk-WJJ5KEOH.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +40 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/scheduler.mjs +15 -0
- package/dist/lib/neutral/scheduler.mjs.map +7 -0
- package/dist/lib/neutral/testing/index.mjs +40 -0
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/atoms.d.ts +8 -0
- package/dist/types/src/atoms.d.ts.map +1 -0
- package/dist/types/src/graph-builder.d.ts +117 -60
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +188 -218
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +7 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/node-matcher.d.ts +244 -0
- package/dist/types/src/node-matcher.d.ts.map +1 -0
- package/dist/types/src/node-matcher.test.d.ts +2 -0
- package/dist/types/src/node-matcher.test.d.ts.map +1 -0
- package/dist/types/src/node.d.ts +50 -5
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/scheduler.browser.d.ts +2 -0
- package/dist/types/src/scheduler.browser.d.ts.map +1 -0
- package/dist/types/src/scheduler.d.ts +8 -0
- package/dist/types/src/scheduler.d.ts.map +1 -0
- package/dist/types/src/stories/EchoGraph.stories.d.ts +6 -13
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/setup-graph-builder.d.ts +31 -0
- package/dist/types/src/testing/setup-graph-builder.d.ts.map +1 -0
- package/dist/types/src/util.d.ts +40 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +53 -42
- package/src/atoms.ts +25 -0
- package/src/graph-builder.test.ts +1193 -126
- package/src/graph-builder.ts +753 -264
- package/src/graph.test.ts +451 -123
- package/src/graph.ts +1057 -407
- package/src/index.ts +10 -3
- package/src/node-matcher.test.ts +301 -0
- package/src/node-matcher.ts +314 -0
- package/src/node.ts +83 -7
- package/src/scheduler.browser.ts +5 -0
- package/src/scheduler.ts +17 -0
- package/src/stories/EchoGraph.stories.tsx +178 -255
- package/src/stories/Tree.tsx +1 -1
- package/src/testing/index.ts +5 -0
- package/src/testing/setup-graph-builder.ts +41 -0
- package/src/util.ts +101 -0
- package/dist/lib/browser/index.mjs +0 -778
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/node/index.cjs +0 -816
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node-esm/index.mjs +0 -780
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
- package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
- package/dist/types/src/signals-integration.test.d.ts +0 -2
- package/dist/types/src/signals-integration.test.d.ts.map +0 -1
- package/dist/types/src/testing.d.ts +0 -5
- package/dist/types/src/testing.d.ts.map +0 -1
- package/src/experimental/graph-projections.test.ts +0 -56
- package/src/signals-integration.test.ts +0 -218
- package/src/testing.ts +0 -20
package/src/util.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { invariant } from '@dxos/invariant';
|
|
6
|
+
|
|
7
|
+
import * as Node from './node';
|
|
8
|
+
|
|
9
|
+
// PRIMARY separates top-level components (e.g., node ID from relation) in compound string keys used within the app-graph package.
|
|
10
|
+
const PRIMARY = '\u0001';
|
|
11
|
+
|
|
12
|
+
// SECONDARY separates sub-components within an encoded value (e.g., relation kind from direction) in the same context.
|
|
13
|
+
const SECONDARY = '\u0002';
|
|
14
|
+
|
|
15
|
+
// PATH separates segments in qualified node IDs (e.g., parent path from local segment).
|
|
16
|
+
const PATH = '/';
|
|
17
|
+
|
|
18
|
+
/** Join parts with the primary separator. */
|
|
19
|
+
export const primaryKey = (...parts: string[]): string => parts.join(PRIMARY);
|
|
20
|
+
|
|
21
|
+
/** Split a key on the primary separator. */
|
|
22
|
+
export const primaryParts = (key: string): string[] => key.split(PRIMARY);
|
|
23
|
+
|
|
24
|
+
/** Join parts with the secondary separator. */
|
|
25
|
+
export const secondaryKey = (...parts: string[]): string => parts.join(SECONDARY);
|
|
26
|
+
|
|
27
|
+
/** Split a key on the secondary separator. */
|
|
28
|
+
export const secondaryParts = (key: string): string[] => key.split(SECONDARY);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Normalize a relation input to a full Relation object.
|
|
32
|
+
*/
|
|
33
|
+
export const normalizeRelation = (relation?: Node.RelationInput): Node.Relation =>
|
|
34
|
+
relation == null ? Node.childRelation() : typeof relation === 'string' ? Node.relation(relation) : relation;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Shallow-compare two values: same reference, or same own-keys with === values.
|
|
38
|
+
*/
|
|
39
|
+
export const shallowEqual = (a: unknown, b: unknown): boolean => {
|
|
40
|
+
if (a === b) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (a == null || b == null || typeof a !== 'object' || typeof b !== 'object') {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const keysA = Object.keys(a as Record<string, unknown>);
|
|
47
|
+
const keysB = Object.keys(b as Record<string, unknown>);
|
|
48
|
+
if (keysA.length !== keysB.length) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return keysA.every((k) => (a as Record<string, unknown>)[k] === (b as Record<string, unknown>)[k]);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns true if two NodeArg arrays are semantically identical (same id, type, data, properties per index).
|
|
56
|
+
* Inline child nodes (the `nodes` field) are compared recursively.
|
|
57
|
+
*/
|
|
58
|
+
export const nodeArgsUnchanged = (prev: Node.NodeArg<any>[], next: Node.NodeArg<any>[]): boolean => {
|
|
59
|
+
if (prev.length !== next.length) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return prev.every((prevNode, idx) => {
|
|
64
|
+
const nextNode = next[idx];
|
|
65
|
+
return (
|
|
66
|
+
prevNode.id === nextNode.id &&
|
|
67
|
+
prevNode.type === nextNode.type &&
|
|
68
|
+
shallowEqual(prevNode.data, nextNode.data) &&
|
|
69
|
+
shallowEqual(prevNode.properties, nextNode.properties) &&
|
|
70
|
+
nodeArgsUnchanged(prevNode.nodes ?? [], nextNode.nodes ?? [])
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Build a qualified node ID by joining path segments.
|
|
77
|
+
*/
|
|
78
|
+
export const qualifyId = (parentId: string, ...segmentIds: string[]): string => [parentId, ...segmentIds].join(PATH);
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Validate that a segment ID does not contain the path separator.
|
|
82
|
+
*/
|
|
83
|
+
export const validateSegmentId = (id: string): void => {
|
|
84
|
+
invariant(!id.includes(PATH), `Node segment ID must not contain '${PATH}': ${id}`);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Extract the parent qualified ID (everything before the last path separator).
|
|
89
|
+
* Returns undefined for IDs with no parent (single segment).
|
|
90
|
+
*/
|
|
91
|
+
export const getParentId = (qualifiedId: string): string | undefined => {
|
|
92
|
+
const lastSlash = qualifiedId.lastIndexOf(PATH);
|
|
93
|
+
return lastSlash > 0 ? qualifiedId.slice(0, lastSlash) : undefined;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Extract the last segment of a qualified ID.
|
|
98
|
+
*/
|
|
99
|
+
export const getSegmentId = (qualifiedId: string): string => {
|
|
100
|
+
return qualifiedId.split(PATH).pop() ?? qualifiedId;
|
|
101
|
+
};
|