@canonical/anatomy-dsl 0.3.0 → 0.5.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.
@@ -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."],
323
+ },
324
+ "spacing.external.block.start": {
325
+ valueKind: "either",
326
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
327
+ },
328
+ "spacing.external.bottom": {
329
+ valueKind: "either",
330
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
331
+ },
332
+ "spacing.external.inline.end": {
333
+ valueKind: "either",
334
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
335
+ },
336
+ "spacing.external.inline.start": {
337
+ valueKind: "either",
338
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
339
+ },
340
+ "spacing.external.left": {
341
+ valueKind: "either",
342
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
343
+ },
344
+ "spacing.external.right": {
345
+ valueKind: "either",
346
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
347
+ },
348
+ "spacing.external.top": {
349
+ valueKind: "either",
350
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
351
+ },
352
+ "spacing.gap": {
353
+ valueKind: "either",
354
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
355
+ },
356
+ "spacing.gap.block": {
357
+ valueKind: "token",
358
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
359
+ },
360
+ "spacing.gap.inline": {
361
+ valueKind: "token",
362
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
363
+ },
364
+ "spacing.internal.block.end": {
365
+ valueKind: "either",
366
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
367
+ },
368
+ "spacing.internal.block.start": {
369
+ valueKind: "either",
370
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
371
+ },
372
+ "spacing.internal.bottom": {
373
+ valueKind: "either",
374
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
375
+ },
376
+ "spacing.internal.inline.end": {
377
+ valueKind: "either",
378
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
379
+ },
380
+ "spacing.internal.inline.start": {
381
+ valueKind: "either",
382
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
383
+ },
384
+ "spacing.internal.left": {
385
+ valueKind: "either",
386
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
387
+ },
388
+ "spacing.internal.top": {
389
+ valueKind: "either",
390
+ tokenNamespace: ["spacing.", "modifier.spacing.", "surface.spacing."],
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 {};