@canonical/anatomy-dsl 0.5.0 → 0.6.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.
@@ -0,0 +1,465 @@
1
+ /**
2
+ * GENERATED by `bun run generate:registry` from definitions/style-keys.yaml.
3
+ * Do not edit: change the roster and regenerate. The Turtle form of the same
4
+ * facts is definitions/registry.ttl, which also carries the roster's
5
+ * provenance, and CI diffs both.
6
+ */
7
+ /** Segments that mark a value as a placeholder rather than a symbol (§4.1). */
8
+ export const PLACEHOLDER_SEGMENTS = [
9
+ "sth",
10
+ "tbd",
11
+ "xxx",
12
+ "todo",
13
+ ];
14
+ /** One entry per canonical style key. The roster is closed. */
15
+ export const STYLE_KEYS = {
16
+ "appearance.background": {
17
+ valueKind: "either",
18
+ tokenNamespace: ["color.", "modifier.color.", "surface.color."],
19
+ },
20
+ "appearance.background.image": {
21
+ valueKind: "primitive",
22
+ tokenNamespace: [],
23
+ },
24
+ "appearance.background.position": {
25
+ valueKind: "primitive",
26
+ tokenNamespace: [],
27
+ },
28
+ "appearance.background.repeat": {
29
+ valueKind: "primitive",
30
+ tokenNamespace: [],
31
+ },
32
+ "appearance.background.size": {
33
+ valueKind: "primitive",
34
+ tokenNamespace: [],
35
+ },
36
+ "appearance.border.block.start.color": {
37
+ valueKind: "token",
38
+ tokenNamespace: ["color.", "modifier.color.", "surface.color."],
39
+ },
40
+ "appearance.border.bottom.color": {
41
+ valueKind: "token",
42
+ tokenNamespace: ["color.", "modifier.color.", "surface.color."],
43
+ },
44
+ "appearance.border.color": {
45
+ valueKind: "either",
46
+ tokenNamespace: ["color.", "modifier.color.", "surface.color."],
47
+ },
48
+ "appearance.border.inline.end.color": {
49
+ valueKind: "token",
50
+ tokenNamespace: ["color.", "modifier.color.", "surface.color."],
51
+ },
52
+ "appearance.border.style": {
53
+ valueKind: "primitive",
54
+ tokenNamespace: [],
55
+ },
56
+ "appearance.border.top.width": {
57
+ valueKind: "either",
58
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
59
+ },
60
+ "appearance.border.width": {
61
+ valueKind: "either",
62
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
63
+ },
64
+ "appearance.native": {
65
+ valueKind: "primitive",
66
+ tokenNamespace: [],
67
+ },
68
+ "appearance.opacity": {
69
+ valueKind: "primitive",
70
+ tokenNamespace: [],
71
+ },
72
+ "appearance.outline.color": {
73
+ valueKind: "either",
74
+ tokenNamespace: ["color.", "modifier.color.", "surface.color."],
75
+ },
76
+ "appearance.outline.offset": {
77
+ valueKind: "either",
78
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
79
+ },
80
+ "appearance.outline.style": {
81
+ valueKind: "primitive",
82
+ tokenNamespace: [],
83
+ },
84
+ "appearance.outline.width": {
85
+ valueKind: "either",
86
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
87
+ },
88
+ "appearance.radius": {
89
+ valueKind: "either",
90
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
91
+ },
92
+ "appearance.visibility": {
93
+ valueKind: "primitive",
94
+ tokenNamespace: [],
95
+ },
96
+ "interaction.cursor": {
97
+ valueKind: "primitive",
98
+ tokenNamespace: [],
99
+ },
100
+ "interaction.pointerEvents": {
101
+ valueKind: "primitive",
102
+ tokenNamespace: [],
103
+ },
104
+ "interaction.resize": {
105
+ valueKind: "primitive",
106
+ tokenNamespace: [],
107
+ },
108
+ "interaction.select": {
109
+ valueKind: "primitive",
110
+ tokenNamespace: [],
111
+ },
112
+ "layout.align": {
113
+ valueKind: "primitive",
114
+ tokenNamespace: [],
115
+ },
116
+ "layout.alignContent": {
117
+ valueKind: "primitive",
118
+ tokenNamespace: [],
119
+ },
120
+ "layout.alignSelf": {
121
+ valueKind: "primitive",
122
+ tokenNamespace: [],
123
+ },
124
+ "layout.boxSizing": {
125
+ valueKind: "primitive",
126
+ tokenNamespace: [],
127
+ },
128
+ "layout.container": {
129
+ valueKind: "primitive",
130
+ tokenNamespace: [],
131
+ },
132
+ "layout.direction": {
133
+ valueKind: "primitive",
134
+ tokenNamespace: [],
135
+ },
136
+ "layout.flex.basis": {
137
+ valueKind: "either",
138
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
139
+ },
140
+ "layout.flex.grow": {
141
+ valueKind: "primitive",
142
+ tokenNamespace: [],
143
+ },
144
+ "layout.flex.shrink": {
145
+ valueKind: "primitive",
146
+ tokenNamespace: [],
147
+ },
148
+ "layout.grid.area": {
149
+ valueKind: "primitive",
150
+ tokenNamespace: [],
151
+ },
152
+ "layout.grid.autoFlow": {
153
+ valueKind: "primitive",
154
+ tokenNamespace: [],
155
+ },
156
+ "layout.grid.autoRows": {
157
+ valueKind: "primitive",
158
+ tokenNamespace: [],
159
+ },
160
+ "layout.grid.column": {
161
+ valueKind: "primitive",
162
+ tokenNamespace: [],
163
+ },
164
+ "layout.grid.columns": {
165
+ valueKind: "primitive",
166
+ tokenNamespace: [],
167
+ },
168
+ "layout.grid.row": {
169
+ valueKind: "primitive",
170
+ tokenNamespace: [],
171
+ },
172
+ "layout.grid.rows": {
173
+ valueKind: "primitive",
174
+ tokenNamespace: [],
175
+ },
176
+ "layout.justify": {
177
+ valueKind: "primitive",
178
+ tokenNamespace: [],
179
+ },
180
+ "layout.listStyle": {
181
+ valueKind: "primitive",
182
+ tokenNamespace: [],
183
+ },
184
+ "layout.objectFit": {
185
+ valueKind: "primitive",
186
+ tokenNamespace: [],
187
+ },
188
+ "layout.offset.block.end": {
189
+ valueKind: "token",
190
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
191
+ },
192
+ "layout.offset.block.start": {
193
+ valueKind: "token",
194
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
195
+ },
196
+ "layout.offset.bottom": {
197
+ valueKind: "either",
198
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
199
+ },
200
+ "layout.offset.inline.start": {
201
+ valueKind: "token",
202
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
203
+ },
204
+ "layout.offset.left": {
205
+ valueKind: "either",
206
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
207
+ },
208
+ "layout.offset.right": {
209
+ valueKind: "either",
210
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
211
+ },
212
+ "layout.offset.top": {
213
+ valueKind: "either",
214
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
215
+ },
216
+ "layout.order": {
217
+ valueKind: "primitive",
218
+ tokenNamespace: [],
219
+ },
220
+ "layout.overflow": {
221
+ valueKind: "primitive",
222
+ tokenNamespace: [],
223
+ },
224
+ "layout.overflow.block": {
225
+ valueKind: "primitive",
226
+ tokenNamespace: [],
227
+ },
228
+ "layout.overflow.inline": {
229
+ valueKind: "primitive",
230
+ tokenNamespace: [],
231
+ },
232
+ "layout.overscroll": {
233
+ valueKind: "primitive",
234
+ tokenNamespace: [],
235
+ },
236
+ "layout.position": {
237
+ valueKind: "primitive",
238
+ tokenNamespace: [],
239
+ },
240
+ "layout.stack": {
241
+ valueKind: "primitive",
242
+ tokenNamespace: [],
243
+ },
244
+ "layout.table.collapse": {
245
+ valueKind: "primitive",
246
+ tokenNamespace: [],
247
+ },
248
+ "layout.table.layout": {
249
+ valueKind: "primitive",
250
+ tokenNamespace: [],
251
+ },
252
+ "layout.table.spacing": {
253
+ valueKind: "primitive",
254
+ tokenNamespace: [],
255
+ },
256
+ "layout.type": {
257
+ valueKind: "primitive",
258
+ tokenNamespace: [],
259
+ },
260
+ "layout.verticalAlign": {
261
+ valueKind: "primitive",
262
+ tokenNamespace: [],
263
+ },
264
+ "layout.wrap": {
265
+ valueKind: "primitive",
266
+ tokenNamespace: [],
267
+ },
268
+ "motion.duration": {
269
+ valueKind: "either",
270
+ tokenNamespace: ["motion.", "modifier.motion.", "surface.motion."],
271
+ },
272
+ "motion.easing": {
273
+ valueKind: "either",
274
+ tokenNamespace: ["motion.", "modifier.motion.", "surface.motion."],
275
+ },
276
+ "motion.property": {
277
+ valueKind: "primitive",
278
+ tokenNamespace: [],
279
+ },
280
+ "size.block": {
281
+ valueKind: "either",
282
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
283
+ },
284
+ "size.height": {
285
+ valueKind: "either",
286
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
287
+ },
288
+ "size.inline": {
289
+ valueKind: "token",
290
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
291
+ },
292
+ "size.max.block": {
293
+ valueKind: "token",
294
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
295
+ },
296
+ "size.max.height": {
297
+ valueKind: "either",
298
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
299
+ },
300
+ "size.max.width": {
301
+ valueKind: "either",
302
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
303
+ },
304
+ "size.min.block": {
305
+ valueKind: "token",
306
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
307
+ },
308
+ "size.min.height": {
309
+ valueKind: "token",
310
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
311
+ },
312
+ "size.min.width": {
313
+ valueKind: "either",
314
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
315
+ },
316
+ "size.width": {
317
+ valueKind: "either",
318
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
319
+ },
320
+ "spacing.external.block.end": {
321
+ valueKind: "either",
322
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
323
+ },
324
+ "spacing.external.block.start": {
325
+ valueKind: "either",
326
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
327
+ },
328
+ "spacing.external.bottom": {
329
+ valueKind: "either",
330
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
331
+ },
332
+ "spacing.external.inline.end": {
333
+ valueKind: "either",
334
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
335
+ },
336
+ "spacing.external.inline.start": {
337
+ valueKind: "either",
338
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
339
+ },
340
+ "spacing.external.left": {
341
+ valueKind: "either",
342
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
343
+ },
344
+ "spacing.external.right": {
345
+ valueKind: "either",
346
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
347
+ },
348
+ "spacing.external.top": {
349
+ valueKind: "either",
350
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
351
+ },
352
+ "spacing.gap": {
353
+ valueKind: "either",
354
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
355
+ },
356
+ "spacing.gap.block": {
357
+ valueKind: "token",
358
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
359
+ },
360
+ "spacing.gap.inline": {
361
+ valueKind: "token",
362
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
363
+ },
364
+ "spacing.internal.block.end": {
365
+ valueKind: "either",
366
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
367
+ },
368
+ "spacing.internal.block.start": {
369
+ valueKind: "either",
370
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
371
+ },
372
+ "spacing.internal.bottom": {
373
+ valueKind: "either",
374
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
375
+ },
376
+ "spacing.internal.inline.end": {
377
+ valueKind: "either",
378
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
379
+ },
380
+ "spacing.internal.inline.start": {
381
+ valueKind: "either",
382
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
383
+ },
384
+ "spacing.internal.left": {
385
+ valueKind: "either",
386
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
387
+ },
388
+ "spacing.internal.top": {
389
+ valueKind: "either",
390
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing.", "dimension.", "modifier.dimension.", "surface.dimension."],
391
+ },
392
+ "typography.align": {
393
+ valueKind: "primitive",
394
+ tokenNamespace: [],
395
+ },
396
+ "typography.color": {
397
+ valueKind: "either",
398
+ tokenNamespace: ["color.", "modifier.color.", "surface.color."],
399
+ },
400
+ "typography.decoration": {
401
+ valueKind: "primitive",
402
+ tokenNamespace: [],
403
+ },
404
+ "typography.decoration.offset": {
405
+ valueKind: "token",
406
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
407
+ },
408
+ "typography.decoration.thickness": {
409
+ valueKind: "either",
410
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
411
+ },
412
+ "typography.direction": {
413
+ valueKind: "primitive",
414
+ tokenNamespace: [],
415
+ },
416
+ "typography.font": {
417
+ valueKind: "either",
418
+ tokenNamespace: ["typography.", "modifier.typography.", "surface.typography."],
419
+ },
420
+ "typography.fontFamily": {
421
+ valueKind: "either",
422
+ tokenNamespace: ["typography.", "modifier.typography.", "surface.typography."],
423
+ },
424
+ "typography.letterSpacing": {
425
+ valueKind: "either",
426
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
427
+ },
428
+ "typography.lineHeight": {
429
+ valueKind: "either",
430
+ tokenNamespace: ["typography.", "modifier.typography.", "surface.typography."],
431
+ },
432
+ "typography.overflow": {
433
+ valueKind: "primitive",
434
+ tokenNamespace: [],
435
+ },
436
+ "typography.size": {
437
+ valueKind: "either",
438
+ tokenNamespace: ["dimension.", "modifier.dimension.", "surface.dimension."],
439
+ },
440
+ "typography.variant.caps": {
441
+ valueKind: "primitive",
442
+ tokenNamespace: [],
443
+ },
444
+ "typography.variant.numeric": {
445
+ valueKind: "primitive",
446
+ tokenNamespace: [],
447
+ },
448
+ "typography.weight": {
449
+ valueKind: "either",
450
+ tokenNamespace: ["typography.", "modifier.typography.", "surface.typography."],
451
+ },
452
+ "typography.whiteSpace": {
453
+ valueKind: "primitive",
454
+ tokenNamespace: [],
455
+ },
456
+ "typography.wrap": {
457
+ valueKind: "primitive",
458
+ tokenNamespace: [],
459
+ },
460
+ };
461
+ /** Whether the key admits a token symbol at all. */
462
+ export function takesToken(key) {
463
+ const entry = STYLE_KEYS[key];
464
+ return entry !== undefined && entry.valueKind !== "primitive";
465
+ }
@@ -0,0 +1,181 @@
1
+ import { takesToken } from "./registry.generated.js";
2
+ const PREFIX = "@prefix : <https://anatomy.canonical.com/> .";
3
+ /** The token graph's namespace, bound where a symbol is consumed. */
4
+ const DT_PREFIX = "@prefix dt: <https://dt.canonical.com/> .";
5
+ const INDENT = " ";
6
+ export function anatomyToTTL(spec) {
7
+ const lines = [];
8
+ lines.push("[] a :Specification ;");
9
+ lines.push(`${INDENT}:rootNode [`);
10
+ writeNode(lines, spec.root, 2);
11
+ lines.push(`${INDENT}] .`);
12
+ const body = lines.join("\n");
13
+ // `dt:` is bound only where the document consumes a symbol: an anatomy of
14
+ // pure structure — a switch and its cases, and nothing else — binds a
15
+ // prefix it never uses otherwise, which every RDF linter reports.
16
+ const header = body.includes(":consumes") ? [PREFIX, DT_PREFIX] : [PREFIX];
17
+ return `${header.join("\n")}\n\n${body}\n`;
18
+ }
19
+ function writeNode(lines, node, depth) {
20
+ if (node.type === "named") {
21
+ writeNamedNode(lines, node, depth);
22
+ }
23
+ else {
24
+ writeAnonymousNode(lines, node, depth);
25
+ }
26
+ const props = node.type === "named" ? (node.props ?? []) : [];
27
+ const styles = node.styles ?? [];
28
+ const edges = node.edges ?? [];
29
+ if (node.projection) {
30
+ writeProjection(lines, node.projection, depth, props.length === 0 && styles.length === 0 && edges.length === 0);
31
+ }
32
+ if (props.length > 0) {
33
+ writeProps(lines, props, depth, styles.length === 0 && edges.length === 0);
34
+ }
35
+ if (styles.length > 0) {
36
+ writeStyles(lines, styles, depth, edges.length === 0);
37
+ }
38
+ if (edges.length > 0) {
39
+ writeEdges(lines, edges, depth);
40
+ }
41
+ }
42
+ function writeNamedNode(lines, node, depth) {
43
+ const indent = INDENT.repeat(depth);
44
+ lines.push(`${indent}a :NamedNode ;`);
45
+ const hasMore = node.projection !== undefined ||
46
+ (node.props && node.props.length > 0) ||
47
+ (node.styles && node.styles.length > 0) ||
48
+ (node.edges && node.edges.length > 0);
49
+ lines.push(`${indent}:uri "${node.uri}"${hasMore ? " ;" : ""}`);
50
+ }
51
+ function writeProps(lines, props, depth, isLast) {
52
+ const indent = INDENT.repeat(depth);
53
+ const innerIndent = INDENT.repeat(depth + 1);
54
+ lines.push(`${indent}:hasProp`);
55
+ for (const [i, prop] of props.entries()) {
56
+ const sep = i < props.length - 1 ? " ," : isLast ? "" : " ;";
57
+ lines.push(`${innerIndent}[ a :Prop ; :propName "${prop.name}" ; :propValue "${prop.value}" ]${sep}`);
58
+ }
59
+ }
60
+ function writeAnonymousNode(lines, node, depth) {
61
+ const indent = INDENT.repeat(depth);
62
+ lines.push(`${indent}a :AnonymousNode ;`);
63
+ const hasMore = node.projection !== undefined ||
64
+ (node.styles && node.styles.length > 0) ||
65
+ (node.edges && node.edges.length > 0);
66
+ lines.push(`${indent}:role "${node.role}"${hasMore ? " ;" : ""}`);
67
+ }
68
+ function writeProjection(lines, projection, depth, isLast) {
69
+ const indent = INDENT.repeat(depth);
70
+ lines.push(`${indent}:hasProjection ${projectionTerm(projection)}${isLast ? "" : " ;"}`);
71
+ }
72
+ function projectionTerm(projection) {
73
+ const parts = ["a :Projection"];
74
+ if (projection.on !== undefined) {
75
+ parts.push(`:projectionType "${projection.on}"`);
76
+ }
77
+ if (projection.field !== undefined) {
78
+ parts.push(`:projectionField "${projection.field}"`);
79
+ }
80
+ return `[ ${parts.join(" ; ")} ]`;
81
+ }
82
+ function writeStyles(lines, styles, depth, isLast) {
83
+ const indent = INDENT.repeat(depth);
84
+ const innerIndent = INDENT.repeat(depth + 1);
85
+ lines.push(`${indent}:hasStyle`);
86
+ for (const [i, style] of styles.entries()) {
87
+ const sep = i < styles.length - 1 ? " ," : isLast ? "" : " ;";
88
+ const statePart = style.state !== undefined ? ` :styleState "${style.state}" ;` : "";
89
+ lines.push(`${innerIndent}[ a :Style ; :styleKey "${style.key}" ;${statePart} :styleValue "${style.value}"${consumesPart(style)} ]${sep}`);
90
+ }
91
+ }
92
+ /**
93
+ * THE SEAM. On a style tuple whose key the registry says takes a token,
94
+ * `:consumes ( dt:a dt:b … )` — an rdf:List of the consumed symbols in
95
+ * fallback order, whose head is the primary symbol. `:styleValue` keeps the
96
+ * authored spelling verbatim beside it, terminal literal included, so the
97
+ * evidence and the queryable form travel together.
98
+ *
99
+ * Nothing is emitted for a key the registry calls `primitive`, and nothing
100
+ * for an `either` key whose value is one primitive — there is no symbol to
101
+ * consume. A token-kind key with no symbols emits none either, and
102
+ * StyleShape's generated disjunction is what turns that into a violation
103
+ * rather than a silence.
104
+ */
105
+ function consumesPart(style) {
106
+ if (style.symbols.length === 0 || !takesToken(style.key))
107
+ return "";
108
+ const members = style.symbols.map((symbol) => `dt:${symbol}`).join(" ");
109
+ return ` ; :consumes ( ${members} )`;
110
+ }
111
+ function writeEdges(lines, edges, depth) {
112
+ const indent = INDENT.repeat(depth);
113
+ for (const [i, edge] of edges.entries()) {
114
+ if (i === 0) {
115
+ lines.push(`${indent}:hasEdge [`);
116
+ }
117
+ else {
118
+ lines.push(`${indent}] , [`);
119
+ }
120
+ writeEdge(lines, edge, depth + 1);
121
+ }
122
+ lines.push(`${indent}]`);
123
+ }
124
+ function writeEdge(lines, edge, depth) {
125
+ const indent = INDENT.repeat(depth);
126
+ lines.push(`${indent}a :Edge ;`);
127
+ if (isSwitch(edge.target)) {
128
+ lines.push(`${indent}:edgeSwitch [`);
129
+ writeSwitch(lines, edge.target, depth + 1);
130
+ lines.push(`${indent}] ;`);
131
+ }
132
+ else {
133
+ lines.push(`${indent}:edgeTarget [`);
134
+ writeNode(lines, edge.target, depth + 1);
135
+ lines.push(`${indent}] ;`);
136
+ }
137
+ writeRelation(lines, edge, depth);
138
+ }
139
+ function writeSwitch(lines, sw, depth) {
140
+ const indent = INDENT.repeat(depth);
141
+ lines.push(`${indent}a :Switch ;`);
142
+ lines.push(`${indent}:discriminator "${sw.discriminator}" ;`);
143
+ for (const [i, sc] of sw.cases.entries()) {
144
+ if (i === 0) {
145
+ lines.push(`${indent}:hasCase [`);
146
+ }
147
+ else {
148
+ lines.push(`${indent}] , [`);
149
+ }
150
+ writeSwitchCase(lines, sc, depth + 1);
151
+ }
152
+ lines.push(`${indent}]`);
153
+ }
154
+ function writeSwitchCase(lines, sc, depth) {
155
+ const indent = INDENT.repeat(depth);
156
+ lines.push(`${indent}a :SwitchCase ;`);
157
+ lines.push(`${indent}:caseNode [`);
158
+ writeNode(lines, sc.node, depth + 1);
159
+ lines.push(`${indent}]`);
160
+ }
161
+ function writeRelation(lines, edge, depth) {
162
+ const indent = INDENT.repeat(depth);
163
+ lines.push(`${indent}:hasRelation [`);
164
+ const inner = INDENT.repeat(depth + 1);
165
+ const { relation } = edge;
166
+ const predicates = ["a :Relation", `:cardinality "${relation.cardinality}"`];
167
+ if (relation.slotName) {
168
+ predicates.push(`:slotName "${relation.slotName}"`);
169
+ }
170
+ if (relation.projection) {
171
+ predicates.push(`:hasProjection ${projectionTerm(relation.projection)}`);
172
+ }
173
+ for (const [i, predicate] of predicates.entries()) {
174
+ const sep = i < predicates.length - 1 ? " ;" : "";
175
+ lines.push(`${inner}${predicate}${sep}`);
176
+ }
177
+ lines.push(`${indent}]`);
178
+ }
179
+ function isSwitch(target) {
180
+ return "discriminator" in target;
181
+ }
@@ -0,0 +1 @@
1
+ export {};