structured-context 0.16.0 → 0.17.1
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/LICENSE +21 -0
- package/README.md +15 -15
- package/dist/api.d.ts +4 -2
- package/dist/api.js +2 -0
- package/dist/browser.d.ts +14 -0
- package/dist/browser.js +13 -0
- package/dist/commands/dump.d.ts +2 -0
- package/dist/commands/dump.js +3 -1
- package/dist/commands/schemas.js +3 -2
- package/dist/commands/spaces.js +4 -6
- package/dist/commands/validate.js +20 -19
- package/dist/config/health.d.ts +10 -6
- package/dist/config/health.js +11 -44
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.js +15 -6
- package/dist/filter/augment-nodes.d.ts +2 -2
- package/dist/filter/augment-nodes.js +2 -2
- package/dist/filter/expand-include.js +2 -2
- package/dist/index.js +9 -1
- package/dist/judge/context.js +1 -1
- package/dist/load-space-graph.js +1 -13
- package/dist/plugins/markdown/parse-embedded.js +4 -4
- package/dist/plugins/miro/cache.js +1 -1
- package/dist/plugins/miro/sync.js +2 -2
- package/dist/read/resolve-graph-edges.js +3 -3
- package/dist/schema/list-schemas.js +2 -2
- package/dist/schema/metadata-contract.d.ts +34 -0
- package/dist/schema/metadata-contract.js +2 -2
- package/dist/schema/validate-graph.d.ts +2 -2
- package/dist/schema/validate-graph.js +4 -4
- package/dist/schemas/generated/space-graph/1.json +216 -0
- package/dist/schemas/generated/space-graph/latest.json +216 -0
- package/dist/space-context.js +11 -1
- package/dist/space-graph-data.d.ts +237 -0
- package/dist/space-graph-data.js +129 -0
- package/dist/space-graph.d.ts +12 -1
- package/dist/space-graph.js +25 -1
- package/dist/testing.js +3 -3
- package/dist/types.d.ts +2 -2
- package/docs/concepts.md +8 -4
- package/package.json +6 -2
- package/schemas/generated/space-graph/1.json +216 -0
- package/schemas/generated/space-graph/latest.json +216 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { type SpaceGraph } from './space-graph';
|
|
2
|
+
import type { Hierarchy, SchemaMetadata, SpaceNode } from './types';
|
|
3
|
+
/** Bump when the shape of SpaceGraphData changes; the generator refuses to overwrite a released version's schema. */
|
|
4
|
+
export declare const SPACE_GRAPH_FORMAT_VERSION = 1;
|
|
5
|
+
/** Folder under `schemas/generated/` holding the format schema: `latest.json` and one frozen file per released version. */
|
|
6
|
+
export declare const SPACE_GRAPH_SCHEMA_DIR = "space-graph";
|
|
7
|
+
/** Schema `$id` for a format version file, e.g. `.../generated/space-graph/1.json`. */
|
|
8
|
+
export declare function spaceGraphSchemaId(file: string): string;
|
|
9
|
+
/** JSON Schema for SpaceGraphData. Written to `schemas/generated/space-graph/` by `bun run generate:schema-meta`. */
|
|
10
|
+
export declare const SPACE_GRAPH_DATA_SCHEMA: {
|
|
11
|
+
readonly $schema: "https://json-schema.org/draft/2020-12/schema";
|
|
12
|
+
readonly title: "structured-context space graph";
|
|
13
|
+
readonly type: "object";
|
|
14
|
+
readonly properties: {
|
|
15
|
+
readonly formatVersion: {
|
|
16
|
+
readonly const: 1;
|
|
17
|
+
};
|
|
18
|
+
readonly hierarchies: {
|
|
19
|
+
readonly type: "array";
|
|
20
|
+
readonly items: {
|
|
21
|
+
readonly type: "object";
|
|
22
|
+
readonly properties: {
|
|
23
|
+
readonly name: {
|
|
24
|
+
readonly type: "string";
|
|
25
|
+
};
|
|
26
|
+
readonly levels: {
|
|
27
|
+
readonly type: "array";
|
|
28
|
+
readonly items: {
|
|
29
|
+
readonly type: "object";
|
|
30
|
+
readonly properties: {
|
|
31
|
+
readonly selfRef: {
|
|
32
|
+
readonly type: "boolean";
|
|
33
|
+
};
|
|
34
|
+
readonly selfRefField: {
|
|
35
|
+
readonly type: "string";
|
|
36
|
+
};
|
|
37
|
+
readonly templateFormat: {
|
|
38
|
+
readonly enum: readonly ["heading", "list", "table", "page"];
|
|
39
|
+
};
|
|
40
|
+
readonly matchers: {
|
|
41
|
+
readonly type: "array";
|
|
42
|
+
readonly items: {
|
|
43
|
+
readonly type: "string";
|
|
44
|
+
readonly minLength: 1;
|
|
45
|
+
};
|
|
46
|
+
readonly minItems: 1;
|
|
47
|
+
};
|
|
48
|
+
readonly embeddedTemplateFields: {
|
|
49
|
+
readonly type: "array";
|
|
50
|
+
readonly items: {
|
|
51
|
+
readonly type: "string";
|
|
52
|
+
readonly minLength: 1;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
readonly field: {
|
|
56
|
+
readonly type: "string";
|
|
57
|
+
readonly minLength: 1;
|
|
58
|
+
};
|
|
59
|
+
readonly fieldOn: {
|
|
60
|
+
readonly enum: readonly ["child", "parent"];
|
|
61
|
+
};
|
|
62
|
+
readonly multiple: {
|
|
63
|
+
readonly type: "boolean";
|
|
64
|
+
};
|
|
65
|
+
readonly type: {
|
|
66
|
+
readonly type: "string";
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
readonly required: readonly ["type", "field", "fieldOn", "multiple", "selfRef"];
|
|
70
|
+
readonly additionalProperties: false;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
readonly allowSkipLevels: {
|
|
74
|
+
readonly type: "boolean";
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
readonly required: readonly ["name", "levels"];
|
|
78
|
+
readonly additionalProperties: false;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
readonly mainHierarchy: {
|
|
82
|
+
readonly type: "string";
|
|
83
|
+
};
|
|
84
|
+
readonly nodes: {
|
|
85
|
+
readonly type: "array";
|
|
86
|
+
readonly items: {
|
|
87
|
+
readonly type: "object";
|
|
88
|
+
readonly properties: {
|
|
89
|
+
readonly id: {
|
|
90
|
+
readonly type: "string";
|
|
91
|
+
};
|
|
92
|
+
readonly title: {
|
|
93
|
+
readonly type: "string";
|
|
94
|
+
};
|
|
95
|
+
readonly schemaData: {
|
|
96
|
+
readonly type: "object";
|
|
97
|
+
};
|
|
98
|
+
readonly linkTargets: {
|
|
99
|
+
readonly type: "array";
|
|
100
|
+
readonly items: {
|
|
101
|
+
readonly type: "string";
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
readonly type: {
|
|
105
|
+
readonly type: "string";
|
|
106
|
+
};
|
|
107
|
+
readonly content: {
|
|
108
|
+
readonly type: "string";
|
|
109
|
+
};
|
|
110
|
+
readonly contentLinks: {
|
|
111
|
+
readonly type: "array";
|
|
112
|
+
readonly items: {
|
|
113
|
+
readonly type: "object";
|
|
114
|
+
readonly properties: {
|
|
115
|
+
readonly linkSyntax: {
|
|
116
|
+
readonly enum: readonly ["wikilink", "markdown"];
|
|
117
|
+
};
|
|
118
|
+
readonly text: {
|
|
119
|
+
readonly type: "string";
|
|
120
|
+
};
|
|
121
|
+
readonly target: {
|
|
122
|
+
readonly type: "string";
|
|
123
|
+
};
|
|
124
|
+
readonly action: {
|
|
125
|
+
readonly enum: readonly ["link", "embed"];
|
|
126
|
+
};
|
|
127
|
+
readonly anchor: {
|
|
128
|
+
readonly type: "string";
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
readonly required: readonly ["text", "target", "action", "linkSyntax"];
|
|
132
|
+
readonly additionalProperties: false;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
readonly source: {
|
|
136
|
+
readonly type: "object";
|
|
137
|
+
readonly properties: {
|
|
138
|
+
readonly file: {
|
|
139
|
+
readonly type: "string";
|
|
140
|
+
};
|
|
141
|
+
readonly line: {
|
|
142
|
+
readonly type: "integer";
|
|
143
|
+
};
|
|
144
|
+
readonly column: {
|
|
145
|
+
readonly type: "integer";
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
readonly required: readonly ["file"];
|
|
149
|
+
readonly additionalProperties: false;
|
|
150
|
+
};
|
|
151
|
+
readonly resolvedType: {
|
|
152
|
+
readonly type: "string";
|
|
153
|
+
};
|
|
154
|
+
readonly resolvedParents: {
|
|
155
|
+
readonly type: "array";
|
|
156
|
+
readonly items: {
|
|
157
|
+
readonly type: "object";
|
|
158
|
+
readonly properties: {
|
|
159
|
+
readonly id: {
|
|
160
|
+
readonly type: "string";
|
|
161
|
+
};
|
|
162
|
+
readonly field: {
|
|
163
|
+
readonly type: "string";
|
|
164
|
+
};
|
|
165
|
+
readonly kind: {
|
|
166
|
+
readonly enum: readonly ["hierarchy", "relationship"];
|
|
167
|
+
};
|
|
168
|
+
readonly hierarchy: {
|
|
169
|
+
readonly type: "string";
|
|
170
|
+
};
|
|
171
|
+
readonly selfRef: {
|
|
172
|
+
readonly type: "boolean";
|
|
173
|
+
};
|
|
174
|
+
readonly fieldOn: {
|
|
175
|
+
readonly enum: readonly ["child", "parent"];
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
readonly required: readonly ["id", "field", "kind", "selfRef", "fieldOn"];
|
|
179
|
+
readonly additionalProperties: false;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
readonly resolvedLinks: {
|
|
183
|
+
readonly type: "array";
|
|
184
|
+
readonly items: {
|
|
185
|
+
readonly type: "object";
|
|
186
|
+
readonly properties: {
|
|
187
|
+
readonly location: {
|
|
188
|
+
readonly enum: readonly ["node", "internal", "external", "system", "protocol"];
|
|
189
|
+
};
|
|
190
|
+
readonly text: {
|
|
191
|
+
readonly type: "string";
|
|
192
|
+
};
|
|
193
|
+
readonly target: {
|
|
194
|
+
readonly type: "string";
|
|
195
|
+
};
|
|
196
|
+
readonly action: {
|
|
197
|
+
readonly enum: readonly ["link", "embed"];
|
|
198
|
+
};
|
|
199
|
+
readonly anchor: {
|
|
200
|
+
readonly type: "string";
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
readonly required: readonly ["text", "target", "action", "location"];
|
|
204
|
+
readonly additionalProperties: false;
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
readonly required: readonly ["id", "title", "schemaData", "linkTargets", "type", "resolvedType", "resolvedParents", "resolvedLinks"];
|
|
209
|
+
readonly additionalProperties: false;
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
readonly required: readonly ["formatVersion", "hierarchies", "nodes"];
|
|
214
|
+
readonly additionalProperties: false;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* A space's nodes and hierarchies as plain JSON, for passing a graph across a process or network boundary.
|
|
218
|
+
*
|
|
219
|
+
* Edges live in each node's resolvedParents, including edges to nodes outside the set. The format names every
|
|
220
|
+
* hierarchy, so the receiver picks which one structures the graph.
|
|
221
|
+
*/
|
|
222
|
+
export type SpaceGraphData = {
|
|
223
|
+
formatVersion: typeof SPACE_GRAPH_FORMAT_VERSION;
|
|
224
|
+
hierarchies: Hierarchy[];
|
|
225
|
+
/** Name of the main hierarchy, if the schema has one. */
|
|
226
|
+
mainHierarchy?: string;
|
|
227
|
+
nodes: SpaceNode[];
|
|
228
|
+
};
|
|
229
|
+
/** Turn a set of nodes and its schema's hierarchies into SpaceGraphData. Pass `graph.nodes.values()` for a filtered graph. */
|
|
230
|
+
export declare function exportSpaceGraph(nodes: Iterable<SpaceNode>, metadata: Pick<SchemaMetadata, 'hierarchy' | 'hierarchies'>): SpaceGraphData;
|
|
231
|
+
/**
|
|
232
|
+
* Build a SpaceGraph from SpaceGraphData, structured by the named hierarchy (default: the main hierarchy).
|
|
233
|
+
* Throws on an unsupported format version or an unknown hierarchy name.
|
|
234
|
+
*/
|
|
235
|
+
export declare function spaceGraphFrom(data: SpaceGraphData, options?: {
|
|
236
|
+
hierarchy?: string;
|
|
237
|
+
}): SpaceGraph;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { EDGE_PROPS, EMBEDDING_PROPS, SCHEMA_META_BASE_URL } from './schema/metadata-contract';
|
|
2
|
+
import { buildSpaceGraph, selectHierarchy } from './space-graph';
|
|
3
|
+
/** Bump when the shape of SpaceGraphData changes; the generator refuses to overwrite a released version's schema. */
|
|
4
|
+
export const SPACE_GRAPH_FORMAT_VERSION = 1;
|
|
5
|
+
/** Folder under `schemas/generated/` holding the format schema: `latest.json` and one frozen file per released version. */
|
|
6
|
+
export const SPACE_GRAPH_SCHEMA_DIR = 'space-graph';
|
|
7
|
+
/** Schema `$id` for a format version file, e.g. `.../generated/space-graph/1.json`. */
|
|
8
|
+
export function spaceGraphSchemaId(file) {
|
|
9
|
+
return `${SCHEMA_META_BASE_URL}/${SPACE_GRAPH_SCHEMA_DIR}/${file}.json`;
|
|
10
|
+
}
|
|
11
|
+
const STRING = { type: 'string' };
|
|
12
|
+
const SOURCE_LOCATION_SCHEMA = {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: { file: STRING, line: { type: 'integer' }, column: { type: 'integer' } },
|
|
15
|
+
required: ['file'],
|
|
16
|
+
additionalProperties: false,
|
|
17
|
+
};
|
|
18
|
+
const CONTENT_LINK_PROPS = {
|
|
19
|
+
text: STRING,
|
|
20
|
+
target: STRING,
|
|
21
|
+
action: { enum: ['link', 'embed'] },
|
|
22
|
+
anchor: STRING,
|
|
23
|
+
};
|
|
24
|
+
const CONTENT_LINK_SCHEMA = {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: { ...CONTENT_LINK_PROPS, linkSyntax: { enum: ['wikilink', 'markdown'] } },
|
|
27
|
+
required: ['text', 'target', 'action', 'linkSyntax'],
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
};
|
|
30
|
+
const RESOLVED_CONTENT_LINK_SCHEMA = {
|
|
31
|
+
type: 'object',
|
|
32
|
+
properties: { ...CONTENT_LINK_PROPS, location: { enum: ['node', 'internal', 'external', 'system', 'protocol'] } },
|
|
33
|
+
required: ['text', 'target', 'action', 'location'],
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
};
|
|
36
|
+
const RESOLVED_PARENT_REF_SCHEMA = {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
id: STRING,
|
|
40
|
+
field: STRING,
|
|
41
|
+
kind: { enum: ['hierarchy', 'relationship'] },
|
|
42
|
+
hierarchy: STRING,
|
|
43
|
+
selfRef: { type: 'boolean' },
|
|
44
|
+
fieldOn: EDGE_PROPS.fieldOn,
|
|
45
|
+
},
|
|
46
|
+
required: ['id', 'field', 'kind', 'selfRef', 'fieldOn'],
|
|
47
|
+
additionalProperties: false,
|
|
48
|
+
};
|
|
49
|
+
const SPACE_NODE_SCHEMA = {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
id: STRING,
|
|
53
|
+
title: STRING,
|
|
54
|
+
schemaData: { type: 'object' },
|
|
55
|
+
linkTargets: { type: 'array', items: STRING },
|
|
56
|
+
type: STRING,
|
|
57
|
+
content: STRING,
|
|
58
|
+
contentLinks: { type: 'array', items: CONTENT_LINK_SCHEMA },
|
|
59
|
+
source: SOURCE_LOCATION_SCHEMA,
|
|
60
|
+
resolvedType: STRING,
|
|
61
|
+
resolvedParents: { type: 'array', items: RESOLVED_PARENT_REF_SCHEMA },
|
|
62
|
+
resolvedLinks: { type: 'array', items: RESOLVED_CONTENT_LINK_SCHEMA },
|
|
63
|
+
},
|
|
64
|
+
required: ['id', 'title', 'schemaData', 'linkTargets', 'type', 'resolvedType', 'resolvedParents', 'resolvedLinks'],
|
|
65
|
+
additionalProperties: false,
|
|
66
|
+
};
|
|
67
|
+
/** A hierarchy level after normalisation: edge fields are always present. */
|
|
68
|
+
const HIERARCHY_LEVEL_SCHEMA = {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
type: STRING,
|
|
72
|
+
...EDGE_PROPS,
|
|
73
|
+
...EMBEDDING_PROPS,
|
|
74
|
+
selfRef: { type: 'boolean' },
|
|
75
|
+
selfRefField: STRING,
|
|
76
|
+
},
|
|
77
|
+
required: ['type', 'field', 'fieldOn', 'multiple', 'selfRef'],
|
|
78
|
+
additionalProperties: false,
|
|
79
|
+
};
|
|
80
|
+
const HIERARCHY_SCHEMA = {
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {
|
|
83
|
+
name: STRING,
|
|
84
|
+
levels: { type: 'array', items: HIERARCHY_LEVEL_SCHEMA },
|
|
85
|
+
allowSkipLevels: { type: 'boolean' },
|
|
86
|
+
},
|
|
87
|
+
required: ['name', 'levels'],
|
|
88
|
+
additionalProperties: false,
|
|
89
|
+
};
|
|
90
|
+
/** JSON Schema for SpaceGraphData. Written to `schemas/generated/space-graph/` by `bun run generate:schema-meta`. */
|
|
91
|
+
export const SPACE_GRAPH_DATA_SCHEMA = {
|
|
92
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
93
|
+
title: 'structured-context space graph',
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
formatVersion: { const: SPACE_GRAPH_FORMAT_VERSION },
|
|
97
|
+
hierarchies: { type: 'array', items: HIERARCHY_SCHEMA },
|
|
98
|
+
mainHierarchy: STRING,
|
|
99
|
+
nodes: { type: 'array', items: SPACE_NODE_SCHEMA },
|
|
100
|
+
},
|
|
101
|
+
required: ['formatVersion', 'hierarchies', 'nodes'],
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
};
|
|
104
|
+
/** Turn a set of nodes and its schema's hierarchies into SpaceGraphData. Pass `graph.nodes.values()` for a filtered graph. */
|
|
105
|
+
export function exportSpaceGraph(nodes, metadata) {
|
|
106
|
+
return {
|
|
107
|
+
formatVersion: SPACE_GRAPH_FORMAT_VERSION,
|
|
108
|
+
hierarchies: metadata.hierarchies ?? [],
|
|
109
|
+
...(metadata.hierarchy ? { mainHierarchy: metadata.hierarchy.name } : {}),
|
|
110
|
+
nodes: [...nodes],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Build a SpaceGraph from SpaceGraphData, structured by the named hierarchy (default: the main hierarchy).
|
|
115
|
+
* Throws on an unsupported format version or an unknown hierarchy name.
|
|
116
|
+
*/
|
|
117
|
+
export function spaceGraphFrom(data, options = {}) {
|
|
118
|
+
if (data.formatVersion !== SPACE_GRAPH_FORMAT_VERSION) {
|
|
119
|
+
throw new Error(`Unsupported space graph format version ${data.formatVersion}; expected ${SPACE_GRAPH_FORMAT_VERSION}.`);
|
|
120
|
+
}
|
|
121
|
+
const metadata = {
|
|
122
|
+
hierarchy: data.hierarchies.find((h) => h.name === data.mainHierarchy),
|
|
123
|
+
hierarchies: data.hierarchies,
|
|
124
|
+
};
|
|
125
|
+
return buildSpaceGraph(data.nodes, selectHierarchy(metadata, options.hierarchy));
|
|
126
|
+
}
|
|
127
|
+
// Fails typecheck when SPACE_GRAPH_DATA_SCHEMA and SpaceGraphData drift apart.
|
|
128
|
+
const _schemaMatchesType = true;
|
|
129
|
+
void _schemaMatchesType;
|
package/dist/space-graph.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type { Hierarchy, NodeId, SpaceNode } from './types';
|
|
1
|
+
import type { Hierarchy, NodeId, ResolvedParentRef, SchemaMetadata, SpaceNode } from './types';
|
|
2
|
+
/** A typed edge between two nodes: a node's resolvedParents entry, with both ends named. */
|
|
3
|
+
export type SpaceEdge = Omit<ResolvedParentRef, 'id'> & {
|
|
4
|
+
parent: NodeId;
|
|
5
|
+
child: NodeId;
|
|
6
|
+
};
|
|
2
7
|
/**
|
|
3
8
|
* A navigable graph over a set of SpaceNodes.
|
|
4
9
|
*
|
|
@@ -21,6 +26,10 @@ export type SpaceGraph = {
|
|
|
21
26
|
readonly hierarchyChildren: ReadonlyMap<NodeId, readonly SpaceNode[]>;
|
|
22
27
|
/** All-edges children map: parent id → direct children connected via any edge (hierarchy + relationship). */
|
|
23
28
|
readonly children: ReadonlyMap<NodeId, readonly SpaceNode[]>;
|
|
29
|
+
/** Parent edges: child id → edges to its parents (hierarchy + relationship), in resolvedParents order. */
|
|
30
|
+
readonly parentEdges: ReadonlyMap<NodeId, readonly SpaceEdge[]>;
|
|
31
|
+
/** Child edges: parent id → edges to its children (hierarchy + relationship). */
|
|
32
|
+
readonly childEdges: ReadonlyMap<NodeId, readonly SpaceEdge[]>;
|
|
24
33
|
/** Set of all node ids that are part of the hierarchy (roots + their descendants + orphans). */
|
|
25
34
|
readonly hierarchyIds: ReadonlySet<NodeId>;
|
|
26
35
|
/** The hierarchy used to build this graph, if the schema has one. */
|
|
@@ -28,3 +37,5 @@ export type SpaceGraph = {
|
|
|
28
37
|
};
|
|
29
38
|
/** Build a SpaceGraph from a flat list of SpaceNodes and the hierarchy to structure it by. */
|
|
30
39
|
export declare function buildSpaceGraph(nodes: SpaceNode[], hierarchy: Hierarchy | undefined): SpaceGraph;
|
|
40
|
+
/** Resolve a hierarchy by name, or the main hierarchy when no name is given. */
|
|
41
|
+
export declare function selectHierarchy(metadata: Pick<SchemaMetadata, 'hierarchy' | 'hierarchies'>, name: string | undefined): Hierarchy | undefined;
|
package/dist/space-graph.js
CHANGED
|
@@ -3,10 +3,12 @@ export function buildSpaceGraph(nodes, hierarchy) {
|
|
|
3
3
|
const levels = hierarchy?.levels ?? [];
|
|
4
4
|
const hierarchyTypes = new Set(levels.map((l) => l.type));
|
|
5
5
|
const rootType = levels[0]?.type;
|
|
6
|
-
const isHierarchyEdge = (r) => r.
|
|
6
|
+
const isHierarchyEdge = (r) => r.kind === 'hierarchy' && r.hierarchy === hierarchy?.name;
|
|
7
7
|
const nodesMap = new Map();
|
|
8
8
|
const hierarchyChildrenMap = new Map();
|
|
9
9
|
const childrenMap = new Map();
|
|
10
|
+
const parentEdgesMap = new Map();
|
|
11
|
+
const childEdgesMap = new Map();
|
|
10
12
|
const hierarchyRoots = [];
|
|
11
13
|
const orphans = [];
|
|
12
14
|
const nonHierarchy = [];
|
|
@@ -15,10 +17,18 @@ export function buildSpaceGraph(nodes, hierarchy) {
|
|
|
15
17
|
nodesMap.set(node.id, node);
|
|
16
18
|
hierarchyChildrenMap.set(node.id, []);
|
|
17
19
|
childrenMap.set(node.id, []);
|
|
20
|
+
parentEdgesMap.set(node.id, []);
|
|
21
|
+
childEdgesMap.set(node.id, []);
|
|
18
22
|
}
|
|
19
23
|
// Second pass: build children maps (inverted from resolvedParents)
|
|
20
24
|
for (const node of nodes) {
|
|
21
25
|
for (const parentRef of node.resolvedParents) {
|
|
26
|
+
const { id: parentId, ...edgeFields } = parentRef;
|
|
27
|
+
const edge = { parent: parentId, child: node.id, ...edgeFields };
|
|
28
|
+
parentEdgesMap.get(node.id).push(edge);
|
|
29
|
+
if (!childEdgesMap.has(parentId))
|
|
30
|
+
childEdgesMap.set(parentId, []);
|
|
31
|
+
childEdgesMap.get(parentId).push(edge);
|
|
22
32
|
// All-edges map
|
|
23
33
|
if (!childrenMap.has(parentRef.id))
|
|
24
34
|
childrenMap.set(parentRef.id, []);
|
|
@@ -78,7 +88,21 @@ export function buildSpaceGraph(nodes, hierarchy) {
|
|
|
78
88
|
nonHierarchy,
|
|
79
89
|
hierarchyChildren: hierarchyChildrenMap,
|
|
80
90
|
children: childrenMap,
|
|
91
|
+
parentEdges: parentEdgesMap,
|
|
92
|
+
childEdges: childEdgesMap,
|
|
81
93
|
hierarchyIds,
|
|
82
94
|
hierarchy,
|
|
83
95
|
};
|
|
84
96
|
}
|
|
97
|
+
/** Resolve a hierarchy by name, or the main hierarchy when no name is given. */
|
|
98
|
+
export function selectHierarchy(metadata, name) {
|
|
99
|
+
if (name === undefined)
|
|
100
|
+
return metadata.hierarchy;
|
|
101
|
+
const hierarchies = metadata.hierarchies ?? [];
|
|
102
|
+
const hierarchy = hierarchies.find((h) => h.name === name);
|
|
103
|
+
if (!hierarchy) {
|
|
104
|
+
const available = hierarchies.map((h) => h.name).join(', ');
|
|
105
|
+
throw new Error(`Unknown hierarchy: "${name}".${available ? ` Available: ${available}` : ' The schema defines no hierarchies.'}`);
|
|
106
|
+
}
|
|
107
|
+
return hierarchy;
|
|
108
|
+
}
|
package/dist/testing.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* Override any field to represent specific edge contexts.
|
|
4
4
|
*/
|
|
5
5
|
export const makeParentRef = (id, overrides = {}) => {
|
|
6
|
-
const
|
|
6
|
+
const kind = overrides.kind ?? 'hierarchy';
|
|
7
7
|
return {
|
|
8
8
|
id: id,
|
|
9
9
|
field: 'parent',
|
|
10
|
-
|
|
11
|
-
...(
|
|
10
|
+
kind,
|
|
11
|
+
...(kind === 'hierarchy' ? { hierarchy: 'main' } : {}),
|
|
12
12
|
selfRef: false,
|
|
13
13
|
fieldOn: 'child',
|
|
14
14
|
...overrides,
|
package/dist/types.d.ts
CHANGED
|
@@ -43,8 +43,8 @@ export type ResolvedParentRef = {
|
|
|
43
43
|
/** The field name that contained the wikilink (e.g. 'parent', 'key_activities', 'produces_data'). */
|
|
44
44
|
field: string;
|
|
45
45
|
/** Whether this edge originates from a hierarchy level or a relationship definition. */
|
|
46
|
-
|
|
47
|
-
/** Name of the hierarchy the edge belongs to. Set only when
|
|
46
|
+
kind: 'hierarchy' | 'relationship';
|
|
47
|
+
/** Name of the hierarchy the edge belongs to. Set only when kind is 'hierarchy'. */
|
|
48
48
|
hierarchy?: string;
|
|
49
49
|
/** Whether the parent and child are the same node type (self-referential edge). */
|
|
50
50
|
selfRef: boolean;
|
package/docs/concepts.md
CHANGED
|
@@ -319,11 +319,15 @@ Each entry is a `ResolvedParentRef` object:
|
|
|
319
319
|
|---|---|---|
|
|
320
320
|
| `id` | `NodeId` | The parent node's `id` |
|
|
321
321
|
| `field` | `string` | The frontmatter field that held the wikilink |
|
|
322
|
-
| `
|
|
323
|
-
| `hierarchy` | `string` | Name of the hierarchy the edge belongs to; present only when `
|
|
322
|
+
| `kind` | `'hierarchy' \| 'relationship'` | Whether the edge came from a hierarchy level or a relationship |
|
|
323
|
+
| `hierarchy` | `string` | Name of the hierarchy the edge belongs to; present only when `kind` is `'hierarchy'` |
|
|
324
324
|
| `selfRef` | `boolean` | Whether the edge is a same-type (self-referential) parent link |
|
|
325
325
|
|
|
326
|
-
The `
|
|
326
|
+
The `kind` and `hierarchy` labels let downstream consumers distinguish edge types and hierarchies without re-inspecting the schema. Validation routes `hierarchy` edges to structural checks within their own hierarchy (parent-type rules, skip-level detection) and `relationship` edges to field reference checks (type-match, missing-target). Tree rendering and rule evaluation use the full set.
|
|
327
|
+
|
|
328
|
+
### Space graph format
|
|
329
|
+
|
|
330
|
+
The **space graph format** is a space's nodes and hierarchies as plain JSON. A program exports it on one side of a process or network boundary and builds a `SpaceGraph` from it on the other. See [api.md](api.md#space-graph-format).
|
|
327
331
|
|
|
328
332
|
### Content links
|
|
329
333
|
|
|
@@ -386,7 +390,7 @@ Each entry in `ancestors[]` or `descendants[]` includes all schema fields of the
|
|
|
386
390
|
| Metadata field | Type | Description |
|
|
387
391
|
|----------------|------|-------------|
|
|
388
392
|
| `_field` | `string` | The edge field name that connects to this ancestor/descendant |
|
|
389
|
-
| `
|
|
393
|
+
| `_kind` | `'hierarchy' \| 'relationship'` | Whether the edge came from a hierarchy or a relationship |
|
|
390
394
|
| `_hierarchy` | `string` | Hierarchy name; present only for hierarchy edges |
|
|
391
395
|
| `_selfRef` | `boolean` | Whether the edge is a same-type (self-referential) link |
|
|
392
396
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "structured-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "Keep your content clean and your thinking clear with assistive tools for structured knowledge",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"types": "./dist/api.d.ts",
|
|
23
23
|
"default": "./dist/api.js"
|
|
24
24
|
},
|
|
25
|
+
"./browser": {
|
|
26
|
+
"types": "./dist/browser.d.ts",
|
|
27
|
+
"default": "./dist/browser.js"
|
|
28
|
+
},
|
|
25
29
|
"./types": {
|
|
26
30
|
"types": "./dist/types.d.ts",
|
|
27
31
|
"default": "./dist/types.js"
|
|
@@ -57,7 +61,6 @@
|
|
|
57
61
|
"@anthropic-ai/claude-agent-sdk": "^0.3.310",
|
|
58
62
|
"@biomejs/biome": "^2.5.15",
|
|
59
63
|
"@types/bun": "^1.4.4",
|
|
60
|
-
"json-schema-to-ts": "^3.1.1",
|
|
61
64
|
"lefthook": "^2.2.2"
|
|
62
65
|
},
|
|
63
66
|
"peerDependencies": {
|
|
@@ -70,6 +73,7 @@
|
|
|
70
73
|
"fast-glob": "^3.3.3",
|
|
71
74
|
"gray-matter": "^4.0.3",
|
|
72
75
|
"js-yaml": "^5.4.3",
|
|
76
|
+
"json-schema-to-ts": "^3.1.1",
|
|
73
77
|
"json5": "^2.2.3",
|
|
74
78
|
"jsonata": "^2.2.1",
|
|
75
79
|
"mdast-util-to-string": "^4.0.0",
|