structured-context 0.15.0 → 0.17.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.
- package/LICENSE +21 -0
- package/README.md +21 -13
- package/dist/api.d.ts +5 -2
- package/dist/api.js +4 -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.d.ts +3 -1
- package/dist/commands/schemas.js +25 -53
- 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 +12 -3
- 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.d.ts +27 -0
- package/dist/schema/list-schemas.js +108 -0
- 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 +5 -1
- package/schemas/generated/space-graph/1.json +216 -0
- package/schemas/generated/space-graph/latest.json +216 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://raw.githubusercontent.com/mindsocket/structured-context/main/schemas/generated/space-graph/1.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"title": "structured-context space graph",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"formatVersion": {
|
|
8
|
+
"const": 1
|
|
9
|
+
},
|
|
10
|
+
"hierarchies": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"name": {
|
|
16
|
+
"type": "string"
|
|
17
|
+
},
|
|
18
|
+
"levels": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"type": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"field": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"minLength": 1
|
|
29
|
+
},
|
|
30
|
+
"fieldOn": {
|
|
31
|
+
"enum": ["child", "parent"]
|
|
32
|
+
},
|
|
33
|
+
"multiple": {
|
|
34
|
+
"type": "boolean"
|
|
35
|
+
},
|
|
36
|
+
"templateFormat": {
|
|
37
|
+
"enum": ["heading", "list", "table", "page"]
|
|
38
|
+
},
|
|
39
|
+
"matchers": {
|
|
40
|
+
"type": "array",
|
|
41
|
+
"items": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"minLength": 1
|
|
44
|
+
},
|
|
45
|
+
"minItems": 1
|
|
46
|
+
},
|
|
47
|
+
"embeddedTemplateFields": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"items": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"minLength": 1
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"selfRef": {
|
|
55
|
+
"type": "boolean"
|
|
56
|
+
},
|
|
57
|
+
"selfRefField": {
|
|
58
|
+
"type": "string"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"required": ["type", "field", "fieldOn", "multiple", "selfRef"],
|
|
62
|
+
"additionalProperties": false
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"allowSkipLevels": {
|
|
66
|
+
"type": "boolean"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"required": ["name", "levels"],
|
|
70
|
+
"additionalProperties": false
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"mainHierarchy": {
|
|
74
|
+
"type": "string"
|
|
75
|
+
},
|
|
76
|
+
"nodes": {
|
|
77
|
+
"type": "array",
|
|
78
|
+
"items": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"id": {
|
|
82
|
+
"type": "string"
|
|
83
|
+
},
|
|
84
|
+
"title": {
|
|
85
|
+
"type": "string"
|
|
86
|
+
},
|
|
87
|
+
"schemaData": {
|
|
88
|
+
"type": "object"
|
|
89
|
+
},
|
|
90
|
+
"linkTargets": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": {
|
|
93
|
+
"type": "string"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"type": {
|
|
97
|
+
"type": "string"
|
|
98
|
+
},
|
|
99
|
+
"content": {
|
|
100
|
+
"type": "string"
|
|
101
|
+
},
|
|
102
|
+
"contentLinks": {
|
|
103
|
+
"type": "array",
|
|
104
|
+
"items": {
|
|
105
|
+
"type": "object",
|
|
106
|
+
"properties": {
|
|
107
|
+
"text": {
|
|
108
|
+
"type": "string"
|
|
109
|
+
},
|
|
110
|
+
"target": {
|
|
111
|
+
"type": "string"
|
|
112
|
+
},
|
|
113
|
+
"action": {
|
|
114
|
+
"enum": ["link", "embed"]
|
|
115
|
+
},
|
|
116
|
+
"anchor": {
|
|
117
|
+
"type": "string"
|
|
118
|
+
},
|
|
119
|
+
"linkSyntax": {
|
|
120
|
+
"enum": ["wikilink", "markdown"]
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"required": ["text", "target", "action", "linkSyntax"],
|
|
124
|
+
"additionalProperties": false
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"source": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"properties": {
|
|
130
|
+
"file": {
|
|
131
|
+
"type": "string"
|
|
132
|
+
},
|
|
133
|
+
"line": {
|
|
134
|
+
"type": "integer"
|
|
135
|
+
},
|
|
136
|
+
"column": {
|
|
137
|
+
"type": "integer"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"required": ["file"],
|
|
141
|
+
"additionalProperties": false
|
|
142
|
+
},
|
|
143
|
+
"resolvedType": {
|
|
144
|
+
"type": "string"
|
|
145
|
+
},
|
|
146
|
+
"resolvedParents": {
|
|
147
|
+
"type": "array",
|
|
148
|
+
"items": {
|
|
149
|
+
"type": "object",
|
|
150
|
+
"properties": {
|
|
151
|
+
"id": {
|
|
152
|
+
"type": "string"
|
|
153
|
+
},
|
|
154
|
+
"field": {
|
|
155
|
+
"type": "string"
|
|
156
|
+
},
|
|
157
|
+
"kind": {
|
|
158
|
+
"enum": ["hierarchy", "relationship"]
|
|
159
|
+
},
|
|
160
|
+
"hierarchy": {
|
|
161
|
+
"type": "string"
|
|
162
|
+
},
|
|
163
|
+
"selfRef": {
|
|
164
|
+
"type": "boolean"
|
|
165
|
+
},
|
|
166
|
+
"fieldOn": {
|
|
167
|
+
"enum": ["child", "parent"]
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"required": ["id", "field", "kind", "selfRef", "fieldOn"],
|
|
171
|
+
"additionalProperties": false
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"resolvedLinks": {
|
|
175
|
+
"type": "array",
|
|
176
|
+
"items": {
|
|
177
|
+
"type": "object",
|
|
178
|
+
"properties": {
|
|
179
|
+
"text": {
|
|
180
|
+
"type": "string"
|
|
181
|
+
},
|
|
182
|
+
"target": {
|
|
183
|
+
"type": "string"
|
|
184
|
+
},
|
|
185
|
+
"action": {
|
|
186
|
+
"enum": ["link", "embed"]
|
|
187
|
+
},
|
|
188
|
+
"anchor": {
|
|
189
|
+
"type": "string"
|
|
190
|
+
},
|
|
191
|
+
"location": {
|
|
192
|
+
"enum": ["node", "internal", "external", "system", "protocol"]
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"required": ["text", "target", "action", "location"],
|
|
196
|
+
"additionalProperties": false
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"required": [
|
|
201
|
+
"id",
|
|
202
|
+
"title",
|
|
203
|
+
"schemaData",
|
|
204
|
+
"linkTargets",
|
|
205
|
+
"type",
|
|
206
|
+
"resolvedType",
|
|
207
|
+
"resolvedParents",
|
|
208
|
+
"resolvedLinks"
|
|
209
|
+
],
|
|
210
|
+
"additionalProperties": false
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
"required": ["formatVersion", "hierarchies", "nodes"],
|
|
215
|
+
"additionalProperties": false
|
|
216
|
+
}
|
package/dist/space-context.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveSchema } from './config';
|
|
2
|
+
import { SctxError } from './errors';
|
|
2
3
|
import { resolveSpacePluginSchemas } from './plugins/util';
|
|
3
4
|
import { loadSchema } from './schema/schema';
|
|
4
5
|
/** Thrown by createSpaceContext when no space matches the given name. */
|
|
@@ -33,7 +34,16 @@ export function createSpaceContext(spaceName, config, options = {}) {
|
|
|
33
34
|
}
|
|
34
35
|
const resolvedSchemaPath = resolveSchema(config, space, { configDir });
|
|
35
36
|
const pluginSchemas = resolveSpacePluginSchemas(space, config, configDir);
|
|
36
|
-
|
|
37
|
+
let loaded;
|
|
38
|
+
try {
|
|
39
|
+
loaded = loadSchema(resolvedSchemaPath, pluginSchemas);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (err instanceof SctxError)
|
|
43
|
+
throw err;
|
|
44
|
+
throw new SctxError('E_SCHEMA_INVALID', `Space "${spaceName}": ${err instanceof Error ? err.message : String(err)}`);
|
|
45
|
+
}
|
|
46
|
+
const { schema, schemaRefRegistry, schemaValidator } = loaded;
|
|
37
47
|
return {
|
|
38
48
|
space,
|
|
39
49
|
config,
|
|
@@ -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;
|