@canonical/anatomy-dsl 0.2.2 → 0.5.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/README.md +240 -23
- package/definitions/lift.fixture.json +216 -0
- package/definitions/ontology.ttl +206 -13
- package/definitions/registry.ttl +659 -0
- package/definitions/shapes.ttl +593 -8
- package/definitions/style-keys.yaml +391 -0
- package/package.json +15 -4
- package/dist/esm/index.js +0 -2
- package/dist/esm/parse.js +0 -72
- package/dist/esm/transform.js +0 -116
- package/dist/esm/types.js +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -2
- package/dist/parse.d.ts +0 -2
- package/dist/parse.js +0 -72
- package/dist/transform.d.ts +0 -2
- package/dist/transform.js +0 -114
- package/dist/types/index.d.ts +0 -3
- package/dist/types/parse.d.ts +0 -2
- package/dist/types/transform.d.ts +0 -2
- package/dist/types/types.d.ts +0 -36
- package/dist/types.d.ts +0 -36
- package/dist/types.js +0 -1
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
# style-keys.yaml — the style-key roster
|
|
3
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
4
|
+
#
|
|
5
|
+
# The style keys an anatomy may bind, and what each one admits as a value.
|
|
6
|
+
# This is the DSL's own vocabulary, held as committed data: it is the single
|
|
7
|
+
# source `bun run generate` projects the graph forms from —
|
|
8
|
+
# `definitions/registry.ttl`, `src/registry.generated.ts`, and the closed
|
|
9
|
+
# `sh:in` of `anatomy:styleKey` plus the `valueKind` `sh:or` in
|
|
10
|
+
# `definitions/shapes.ttl` — and CI regenerates all four and diffs them, so
|
|
11
|
+
# an edit here that is not reflected in the graph is a red bar.
|
|
12
|
+
#
|
|
13
|
+
# ───────────────────────────────────────────────────────────────────────────
|
|
14
|
+
# PROVENANCE — this roster was measured, not designed
|
|
15
|
+
# ───────────────────────────────────────────────────────────────────────────
|
|
16
|
+
#
|
|
17
|
+
# The 111 keys below are the right-hand column of a table whose left-hand
|
|
18
|
+
# column was every CSS property bound on a component selector across the 89
|
|
19
|
+
# published component stylesheets of the reference packages named in
|
|
20
|
+
# `provenance.packages`, at the exact versions stated, measured on
|
|
21
|
+
# 2026-09-10. A key exists because an implementation binds the property,
|
|
22
|
+
# never because the vocabulary looked incomplete — and `valueKind` below is
|
|
23
|
+
# that measurement's reading of what the property carries, not an opinion
|
|
24
|
+
# about it.
|
|
25
|
+
#
|
|
26
|
+
# THE MEASUREMENT ITSELF NO LONGER LIVES HERE. The property census and the
|
|
27
|
+
# CSS reader that fed it moved to `canonical/design-system`, where the
|
|
28
|
+
# reference stylesheets are already an input and the only consumer lives;
|
|
29
|
+
# this package is a YAML/Turtle meta-model and reads no CSS at all. So a
|
|
30
|
+
# re-measurement — a reference version bumped, a component added — happens
|
|
31
|
+
# there and arrives here as a reviewed edit to this file. In this
|
|
32
|
+
# repository's history, `git log -- src/census.ts src/stylesheet.ts` reaches
|
|
33
|
+
# the code that took the measurement.
|
|
34
|
+
#
|
|
35
|
+
# ───────────────────────────────────────────────────────────────────────────
|
|
36
|
+
# HOW A KEY IS WRITTEN
|
|
37
|
+
# ───────────────────────────────────────────────────────────────────────────
|
|
38
|
+
#
|
|
39
|
+
# valueKind: what the key admits — `token` (a symbol, or a fallback list
|
|
40
|
+
# of symbols ending in at most one primitive), `primitive` (a
|
|
41
|
+
# literal the implementation writes as it stands), or `either`.
|
|
42
|
+
# As measured: a key whose every reference value read a
|
|
43
|
+
# `var()` is `token`, one where a literal appeared too is
|
|
44
|
+
# `either`, one that took no symbol at all is `primitive`.
|
|
45
|
+
# namespace: the dotted prefix whose symbols the key admits, ending in a
|
|
46
|
+
# dot. Required on a `token` or `either` key and forbidden on
|
|
47
|
+
# a `primitive` one — the generator fails on either mismatch.
|
|
48
|
+
# It is projected into the three spellings a channel binding
|
|
49
|
+
# needs: `N.`, `modifier.N.` and `surface.N.`, because a
|
|
50
|
+
# channel of a symbol in `N.` is what the anatomy consumes
|
|
51
|
+
# where the implementation reads the channel.
|
|
52
|
+
# why: required on a `primitive` key whose reference values read a
|
|
53
|
+
# `var()` anyway — a component-local count, an asset — and
|
|
54
|
+
# emitted as the key's `rdfs:comment`, so the exception is
|
|
55
|
+
# stated and not silent. Forbidden on a key that takes a token.
|
|
56
|
+
#
|
|
57
|
+
# `spacing.*` keys admit `spacing.` alone and never `dimension.`: the
|
|
58
|
+
# reference binds `dimension.*` there throughout, and that population is
|
|
59
|
+
# the register's to carry rather than the roster's to bless.
|
|
60
|
+
#
|
|
61
|
+
# `motion.` is declared as a namespace though no stratum publishes one yet,
|
|
62
|
+
# so a `motion.duration.fast` binding is admitted and its absence is a
|
|
63
|
+
# register row. `shadow.` is NOT declared, for the same reason in reverse —
|
|
64
|
+
# nothing names it — so no shadow key is in the roster.
|
|
65
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
66
|
+
|
|
67
|
+
version: 1
|
|
68
|
+
|
|
69
|
+
# Where the roster came from. `keys` is asserted against the roster's own
|
|
70
|
+
# length by the generator, so the stated number cannot drift from the data,
|
|
71
|
+
# and the whole block is rendered into `registry.ttl`'s header, where a
|
|
72
|
+
# reader of the graph form meets it too.
|
|
73
|
+
provenance:
|
|
74
|
+
keys: 111
|
|
75
|
+
stylesheets: 89
|
|
76
|
+
measured: "2026-09-10"
|
|
77
|
+
measurement: canonical/design-system
|
|
78
|
+
packages:
|
|
79
|
+
- "@canonical/react-ds-global@0.37.0"
|
|
80
|
+
- "@canonical/react-ds-global-form@0.37.0"
|
|
81
|
+
- "@canonical/lit-ds-prototype@0.37.0"
|
|
82
|
+
- "@canonical/react-ds-app-launchpad@0.37.0"
|
|
83
|
+
|
|
84
|
+
# Placeholder segments. A value that satisfies the symbol grammar but carries
|
|
85
|
+
# one of these is a placeholder rather than a symbol: `dimension.radius.sth`
|
|
86
|
+
# parses and is then rejected on this second test, so the list is data and
|
|
87
|
+
# never a rule in the parser.
|
|
88
|
+
placeholders:
|
|
89
|
+
- sth
|
|
90
|
+
- tbd
|
|
91
|
+
- xxx
|
|
92
|
+
- todo
|
|
93
|
+
|
|
94
|
+
# ───────────────────────────────────────────────────────────────────────────
|
|
95
|
+
# THE ROSTER
|
|
96
|
+
# ───────────────────────────────────────────────────────────────────────────
|
|
97
|
+
keys:
|
|
98
|
+
appearance.background:
|
|
99
|
+
valueKind: either
|
|
100
|
+
namespace: color.
|
|
101
|
+
appearance.background.image:
|
|
102
|
+
valueKind: primitive
|
|
103
|
+
why: "a url() or a gradient is an asset or a function, never a symbol"
|
|
104
|
+
appearance.background.position:
|
|
105
|
+
valueKind: primitive
|
|
106
|
+
why: "a background position is geometry; --select-caret-half is a component-local size"
|
|
107
|
+
appearance.background.repeat:
|
|
108
|
+
valueKind: primitive
|
|
109
|
+
appearance.background.size:
|
|
110
|
+
valueKind: primitive
|
|
111
|
+
why: "a background size is geometry; --select-caret-half is a component-local size"
|
|
112
|
+
appearance.border.block.start.color:
|
|
113
|
+
valueKind: token
|
|
114
|
+
namespace: color.
|
|
115
|
+
appearance.border.bottom.color:
|
|
116
|
+
valueKind: token
|
|
117
|
+
namespace: color.
|
|
118
|
+
appearance.border.color:
|
|
119
|
+
valueKind: either
|
|
120
|
+
namespace: color.
|
|
121
|
+
appearance.border.inline.end.color:
|
|
122
|
+
valueKind: token
|
|
123
|
+
namespace: color.
|
|
124
|
+
appearance.border.style:
|
|
125
|
+
valueKind: primitive
|
|
126
|
+
why: "a line style is a keyword vocabulary; the var() slots the reference splits into here are component-local"
|
|
127
|
+
appearance.border.top.width:
|
|
128
|
+
valueKind: either
|
|
129
|
+
namespace: dimension.
|
|
130
|
+
appearance.border.width:
|
|
131
|
+
valueKind: either
|
|
132
|
+
namespace: dimension.
|
|
133
|
+
appearance.native:
|
|
134
|
+
valueKind: primitive
|
|
135
|
+
appearance.opacity:
|
|
136
|
+
valueKind: primitive
|
|
137
|
+
why: "an opacity is a number the implementation writes; --form-input-opacity-disabled is component-local"
|
|
138
|
+
appearance.outline.color:
|
|
139
|
+
valueKind: either
|
|
140
|
+
namespace: color.
|
|
141
|
+
appearance.outline.offset:
|
|
142
|
+
valueKind: either
|
|
143
|
+
namespace: dimension.
|
|
144
|
+
appearance.outline.style:
|
|
145
|
+
valueKind: primitive
|
|
146
|
+
appearance.outline.width:
|
|
147
|
+
valueKind: either
|
|
148
|
+
namespace: dimension.
|
|
149
|
+
appearance.radius:
|
|
150
|
+
valueKind: either
|
|
151
|
+
namespace: dimension.
|
|
152
|
+
appearance.visibility:
|
|
153
|
+
valueKind: primitive
|
|
154
|
+
|
|
155
|
+
interaction.cursor:
|
|
156
|
+
valueKind: primitive
|
|
157
|
+
interaction.pointerEvents:
|
|
158
|
+
valueKind: primitive
|
|
159
|
+
interaction.resize:
|
|
160
|
+
valueKind: primitive
|
|
161
|
+
interaction.select:
|
|
162
|
+
valueKind: primitive
|
|
163
|
+
|
|
164
|
+
layout.align:
|
|
165
|
+
valueKind: primitive
|
|
166
|
+
layout.alignContent:
|
|
167
|
+
valueKind: primitive
|
|
168
|
+
layout.alignSelf:
|
|
169
|
+
valueKind: primitive
|
|
170
|
+
layout.boxSizing:
|
|
171
|
+
valueKind: primitive
|
|
172
|
+
layout.container:
|
|
173
|
+
valueKind: primitive
|
|
174
|
+
layout.direction:
|
|
175
|
+
valueKind: primitive
|
|
176
|
+
layout.flex.basis:
|
|
177
|
+
valueKind: either
|
|
178
|
+
namespace: dimension.
|
|
179
|
+
layout.flex.grow:
|
|
180
|
+
valueKind: primitive
|
|
181
|
+
layout.flex.shrink:
|
|
182
|
+
valueKind: primitive
|
|
183
|
+
layout.grid.area:
|
|
184
|
+
valueKind: primitive
|
|
185
|
+
layout.grid.autoFlow:
|
|
186
|
+
valueKind: primitive
|
|
187
|
+
layout.grid.autoRows:
|
|
188
|
+
valueKind: primitive
|
|
189
|
+
layout.grid.column:
|
|
190
|
+
valueKind: primitive
|
|
191
|
+
why: "a track line or span is structure; --card-span and --form-field-columns are component-local counts, not symbols"
|
|
192
|
+
layout.grid.columns:
|
|
193
|
+
valueKind: primitive
|
|
194
|
+
why: "a track list is structure; --choices-columns is a component-local count"
|
|
195
|
+
layout.grid.row:
|
|
196
|
+
valueKind: primitive
|
|
197
|
+
layout.grid.rows:
|
|
198
|
+
valueKind: primitive
|
|
199
|
+
layout.justify:
|
|
200
|
+
valueKind: primitive
|
|
201
|
+
layout.listStyle:
|
|
202
|
+
valueKind: primitive
|
|
203
|
+
layout.objectFit:
|
|
204
|
+
valueKind: primitive
|
|
205
|
+
layout.offset.block.end:
|
|
206
|
+
valueKind: token
|
|
207
|
+
namespace: dimension.
|
|
208
|
+
layout.offset.block.start:
|
|
209
|
+
valueKind: token
|
|
210
|
+
namespace: dimension.
|
|
211
|
+
layout.offset.bottom:
|
|
212
|
+
valueKind: either
|
|
213
|
+
namespace: dimension.
|
|
214
|
+
layout.offset.inline.start:
|
|
215
|
+
valueKind: token
|
|
216
|
+
namespace: dimension.
|
|
217
|
+
layout.offset.left:
|
|
218
|
+
valueKind: either
|
|
219
|
+
namespace: dimension.
|
|
220
|
+
layout.offset.right:
|
|
221
|
+
valueKind: either
|
|
222
|
+
namespace: dimension.
|
|
223
|
+
layout.offset.top:
|
|
224
|
+
valueKind: either
|
|
225
|
+
namespace: dimension.
|
|
226
|
+
layout.order:
|
|
227
|
+
valueKind: primitive
|
|
228
|
+
layout.overflow:
|
|
229
|
+
valueKind: primitive
|
|
230
|
+
layout.overflow.block:
|
|
231
|
+
valueKind: primitive
|
|
232
|
+
layout.overflow.inline:
|
|
233
|
+
valueKind: primitive
|
|
234
|
+
layout.overscroll:
|
|
235
|
+
valueKind: primitive
|
|
236
|
+
layout.position:
|
|
237
|
+
valueKind: primitive
|
|
238
|
+
layout.stack:
|
|
239
|
+
valueKind: primitive
|
|
240
|
+
why: "stacking order is structure; --z-index-overlay is a component-local scale, not a symbol"
|
|
241
|
+
layout.table.collapse:
|
|
242
|
+
valueKind: primitive
|
|
243
|
+
layout.table.layout:
|
|
244
|
+
valueKind: primitive
|
|
245
|
+
layout.table.spacing:
|
|
246
|
+
valueKind: primitive
|
|
247
|
+
layout.type:
|
|
248
|
+
valueKind: primitive
|
|
249
|
+
layout.verticalAlign:
|
|
250
|
+
valueKind: primitive
|
|
251
|
+
layout.wrap:
|
|
252
|
+
valueKind: primitive
|
|
253
|
+
|
|
254
|
+
motion.duration:
|
|
255
|
+
valueKind: either
|
|
256
|
+
namespace: motion.
|
|
257
|
+
motion.easing:
|
|
258
|
+
valueKind: either
|
|
259
|
+
namespace: motion.
|
|
260
|
+
motion.property:
|
|
261
|
+
valueKind: primitive
|
|
262
|
+
|
|
263
|
+
size.block:
|
|
264
|
+
valueKind: either
|
|
265
|
+
namespace: dimension.
|
|
266
|
+
size.height:
|
|
267
|
+
valueKind: either
|
|
268
|
+
namespace: dimension.
|
|
269
|
+
size.inline:
|
|
270
|
+
valueKind: token
|
|
271
|
+
namespace: dimension.
|
|
272
|
+
size.max.block:
|
|
273
|
+
valueKind: token
|
|
274
|
+
namespace: dimension.
|
|
275
|
+
size.max.height:
|
|
276
|
+
valueKind: either
|
|
277
|
+
namespace: dimension.
|
|
278
|
+
size.max.width:
|
|
279
|
+
valueKind: either
|
|
280
|
+
namespace: dimension.
|
|
281
|
+
size.min.block:
|
|
282
|
+
valueKind: token
|
|
283
|
+
namespace: dimension.
|
|
284
|
+
size.min.height:
|
|
285
|
+
valueKind: token
|
|
286
|
+
namespace: dimension.
|
|
287
|
+
size.min.width:
|
|
288
|
+
valueKind: either
|
|
289
|
+
namespace: dimension.
|
|
290
|
+
size.width:
|
|
291
|
+
valueKind: either
|
|
292
|
+
namespace: dimension.
|
|
293
|
+
|
|
294
|
+
spacing.external.block.end:
|
|
295
|
+
valueKind: either
|
|
296
|
+
namespace: spacing.
|
|
297
|
+
spacing.external.block.start:
|
|
298
|
+
valueKind: either
|
|
299
|
+
namespace: spacing.
|
|
300
|
+
spacing.external.bottom:
|
|
301
|
+
valueKind: either
|
|
302
|
+
namespace: spacing.
|
|
303
|
+
spacing.external.inline.end:
|
|
304
|
+
valueKind: either
|
|
305
|
+
namespace: spacing.
|
|
306
|
+
spacing.external.inline.start:
|
|
307
|
+
valueKind: either
|
|
308
|
+
namespace: spacing.
|
|
309
|
+
spacing.external.left:
|
|
310
|
+
valueKind: either
|
|
311
|
+
namespace: spacing.
|
|
312
|
+
spacing.external.right:
|
|
313
|
+
valueKind: either
|
|
314
|
+
namespace: spacing.
|
|
315
|
+
spacing.external.top:
|
|
316
|
+
valueKind: either
|
|
317
|
+
namespace: spacing.
|
|
318
|
+
spacing.gap:
|
|
319
|
+
valueKind: either
|
|
320
|
+
namespace: spacing.
|
|
321
|
+
spacing.gap.block:
|
|
322
|
+
valueKind: token
|
|
323
|
+
namespace: spacing.
|
|
324
|
+
spacing.gap.inline:
|
|
325
|
+
valueKind: token
|
|
326
|
+
namespace: spacing.
|
|
327
|
+
spacing.internal.block.end:
|
|
328
|
+
valueKind: either
|
|
329
|
+
namespace: spacing.
|
|
330
|
+
spacing.internal.block.start:
|
|
331
|
+
valueKind: either
|
|
332
|
+
namespace: spacing.
|
|
333
|
+
spacing.internal.bottom:
|
|
334
|
+
valueKind: either
|
|
335
|
+
namespace: spacing.
|
|
336
|
+
spacing.internal.inline.end:
|
|
337
|
+
valueKind: either
|
|
338
|
+
namespace: spacing.
|
|
339
|
+
spacing.internal.inline.start:
|
|
340
|
+
valueKind: either
|
|
341
|
+
namespace: spacing.
|
|
342
|
+
spacing.internal.left:
|
|
343
|
+
valueKind: either
|
|
344
|
+
namespace: spacing.
|
|
345
|
+
spacing.internal.top:
|
|
346
|
+
valueKind: either
|
|
347
|
+
namespace: spacing.
|
|
348
|
+
|
|
349
|
+
typography.align:
|
|
350
|
+
valueKind: primitive
|
|
351
|
+
typography.color:
|
|
352
|
+
valueKind: either
|
|
353
|
+
namespace: color.
|
|
354
|
+
typography.decoration:
|
|
355
|
+
valueKind: primitive
|
|
356
|
+
typography.decoration.offset:
|
|
357
|
+
valueKind: token
|
|
358
|
+
namespace: dimension.
|
|
359
|
+
typography.decoration.thickness:
|
|
360
|
+
valueKind: either
|
|
361
|
+
namespace: dimension.
|
|
362
|
+
typography.direction:
|
|
363
|
+
valueKind: primitive
|
|
364
|
+
typography.font:
|
|
365
|
+
valueKind: either
|
|
366
|
+
namespace: typography.
|
|
367
|
+
typography.fontFamily:
|
|
368
|
+
valueKind: either
|
|
369
|
+
namespace: typography.
|
|
370
|
+
typography.letterSpacing:
|
|
371
|
+
valueKind: either
|
|
372
|
+
namespace: dimension.
|
|
373
|
+
typography.lineHeight:
|
|
374
|
+
valueKind: either
|
|
375
|
+
namespace: typography.
|
|
376
|
+
typography.overflow:
|
|
377
|
+
valueKind: primitive
|
|
378
|
+
typography.size:
|
|
379
|
+
valueKind: either
|
|
380
|
+
namespace: dimension.
|
|
381
|
+
typography.variant.caps:
|
|
382
|
+
valueKind: primitive
|
|
383
|
+
typography.variant.numeric:
|
|
384
|
+
valueKind: primitive
|
|
385
|
+
typography.weight:
|
|
386
|
+
valueKind: either
|
|
387
|
+
namespace: typography.
|
|
388
|
+
typography.whiteSpace:
|
|
389
|
+
valueKind: primitive
|
|
390
|
+
typography.wrap:
|
|
391
|
+
valueKind: primitive
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonical/anatomy-dsl",
|
|
3
3
|
"description": "Anatomy DSL meta-model: TypeScript types mirroring the OWL ontology, and a YAML-to-Turtle transform",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/types/index.d.ts",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./dist/types/index.d.ts",
|
|
11
11
|
"import": "./dist/esm/index.js"
|
|
12
|
-
}
|
|
12
|
+
},
|
|
13
|
+
"./definitions/*": "./definitions/*"
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
15
16
|
"dist",
|
|
@@ -21,17 +22,27 @@
|
|
|
21
22
|
"check": "biome check && tsc --noEmit",
|
|
22
23
|
"check:fix": "biome check --write",
|
|
23
24
|
"check:ts": "tsc --noEmit",
|
|
25
|
+
"generate:registry": "bun run src/generate.ts registry",
|
|
26
|
+
"generate:shapes": "bun run src/generate.ts shapes",
|
|
27
|
+
"generate": "bun run src/generate.ts",
|
|
24
28
|
"test": "vitest run",
|
|
25
29
|
"test:watch": "vitest",
|
|
26
30
|
"test:coverage": "vitest run --coverage"
|
|
27
31
|
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"yaml": "^2.7.1"
|
|
34
|
+
},
|
|
28
35
|
"devDependencies": {
|
|
29
36
|
"@biomejs/biome": "^2.4.6",
|
|
30
37
|
"@canonical/biome-config": "^0.17.1",
|
|
38
|
+
"@canonical/token-ontology": "^0.10.1",
|
|
31
39
|
"@canonical/typescript-config": "^0.17.1",
|
|
40
|
+
"@types/n3": "^1.26.3",
|
|
41
|
+
"@types/node": "^26.4.0",
|
|
32
42
|
"expect-type": "^1.3.0",
|
|
43
|
+
"n3": "^1.26.0",
|
|
44
|
+
"rdf-validate-shacl": "^0.6.5",
|
|
33
45
|
"typescript": "^5.9.3",
|
|
34
|
-
"vitest": "^4.0.18"
|
|
35
|
-
"yaml": "^2.7.1"
|
|
46
|
+
"vitest": "^4.0.18"
|
|
36
47
|
}
|
|
37
48
|
}
|
package/dist/esm/index.js
DELETED
package/dist/esm/parse.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
export function parseAnatomyYAML(raw) {
|
|
2
|
-
const doc = raw;
|
|
3
|
-
return {
|
|
4
|
-
root: toNamedNode(doc.node),
|
|
5
|
-
};
|
|
6
|
-
}
|
|
7
|
-
function toNamedNode(raw) {
|
|
8
|
-
return {
|
|
9
|
-
type: "named",
|
|
10
|
-
uri: raw.uri,
|
|
11
|
-
...(raw.styles ? { styles: toStyles(raw.styles) } : {}),
|
|
12
|
-
...(raw.edges ? { edges: raw.edges.map(toEdge) } : {}),
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
function toNode(raw) {
|
|
16
|
-
if ("uri" in raw && raw.uri) {
|
|
17
|
-
return toNamedNode(raw);
|
|
18
|
-
}
|
|
19
|
-
const anon = raw;
|
|
20
|
-
return {
|
|
21
|
-
type: "anonymous",
|
|
22
|
-
role: anon.role,
|
|
23
|
-
...(anon.styles ? { styles: toStyles(anon.styles) } : {}),
|
|
24
|
-
...(anon.edges ? { edges: anon.edges.map(toEdge) } : {}),
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function toStyles(raw) {
|
|
28
|
-
return Object.entries(raw).map(([key, value]) => ({
|
|
29
|
-
key,
|
|
30
|
-
value: String(value),
|
|
31
|
-
}));
|
|
32
|
-
}
|
|
33
|
-
function toEdge(raw) {
|
|
34
|
-
let target;
|
|
35
|
-
if (raw.switch) {
|
|
36
|
-
target = toSwitch(raw.switch);
|
|
37
|
-
}
|
|
38
|
-
else if (raw.node) {
|
|
39
|
-
target = toNode(raw.node);
|
|
40
|
-
}
|
|
41
|
-
else if (raw.uri) {
|
|
42
|
-
target = { type: "named", uri: raw.uri };
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
throw new Error("Edge must have node, uri, or switch");
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
target,
|
|
49
|
-
relation: toRelation(raw.relation),
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
function toSwitch(raw) {
|
|
53
|
-
return {
|
|
54
|
-
discriminator: raw.on,
|
|
55
|
-
cases: raw.cases.map(toSwitchCase),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function toSwitchCase(raw) {
|
|
59
|
-
if (raw.uri !== undefined) {
|
|
60
|
-
const node = { type: "named", uri: raw.uri };
|
|
61
|
-
return { value: raw.uri, node };
|
|
62
|
-
}
|
|
63
|
-
const node = toNode(raw.node);
|
|
64
|
-
const value = node.type === "named" ? node.uri : node.role;
|
|
65
|
-
return { value, node };
|
|
66
|
-
}
|
|
67
|
-
function toRelation(raw) {
|
|
68
|
-
return {
|
|
69
|
-
cardinality: raw.cardinality,
|
|
70
|
-
...(raw.slotName ? { slotName: raw.slotName } : {}),
|
|
71
|
-
};
|
|
72
|
-
}
|
package/dist/esm/transform.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
const PREFIX = "@prefix : <http://anatomy-dsl.example.org/ontology#> .";
|
|
2
|
-
const INDENT = " ";
|
|
3
|
-
export function anatomyToTTL(spec) {
|
|
4
|
-
const lines = [PREFIX, ""];
|
|
5
|
-
lines.push("[] a :Specification ;");
|
|
6
|
-
lines.push(`${INDENT}:rootNode [`);
|
|
7
|
-
writeNode(lines, spec.root, 2);
|
|
8
|
-
lines.push(`${INDENT}] .`);
|
|
9
|
-
return `${lines.join("\n")}\n`;
|
|
10
|
-
}
|
|
11
|
-
function writeNode(lines, node, depth) {
|
|
12
|
-
if (node.type === "named") {
|
|
13
|
-
writeNamedNode(lines, node, depth);
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
writeAnonymousNode(lines, node, depth);
|
|
17
|
-
}
|
|
18
|
-
const styles = node.styles ?? [];
|
|
19
|
-
const edges = node.edges ?? [];
|
|
20
|
-
if (styles.length > 0) {
|
|
21
|
-
writeStyles(lines, styles, depth, edges.length === 0);
|
|
22
|
-
}
|
|
23
|
-
if (edges.length > 0) {
|
|
24
|
-
writeEdges(lines, edges, depth);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function writeNamedNode(lines, node, depth) {
|
|
28
|
-
const indent = INDENT.repeat(depth);
|
|
29
|
-
lines.push(`${indent}a :NamedNode ;`);
|
|
30
|
-
const hasMore = (node.styles && node.styles.length > 0) ||
|
|
31
|
-
(node.edges && node.edges.length > 0);
|
|
32
|
-
lines.push(`${indent}:uri "${node.uri}"${hasMore ? " ;" : ""}`);
|
|
33
|
-
}
|
|
34
|
-
function writeAnonymousNode(lines, node, depth) {
|
|
35
|
-
const indent = INDENT.repeat(depth);
|
|
36
|
-
lines.push(`${indent}a :AnonymousNode ;`);
|
|
37
|
-
const hasMore = (node.styles && node.styles.length > 0) ||
|
|
38
|
-
(node.edges && node.edges.length > 0);
|
|
39
|
-
lines.push(`${indent}:role "${node.role}"${hasMore ? " ;" : ""}`);
|
|
40
|
-
}
|
|
41
|
-
function writeStyles(lines, styles, depth, isLast) {
|
|
42
|
-
const indent = INDENT.repeat(depth);
|
|
43
|
-
const innerIndent = INDENT.repeat(depth + 1);
|
|
44
|
-
lines.push(`${indent}:hasStyle`);
|
|
45
|
-
for (const [i, style] of styles.entries()) {
|
|
46
|
-
const sep = i < styles.length - 1 ? " ," : isLast ? "" : " ;";
|
|
47
|
-
lines.push(`${innerIndent}[ :styleKey "${style.key}" ; :styleValue "${style.value}" ]${sep}`);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function writeEdges(lines, edges, depth) {
|
|
51
|
-
const indent = INDENT.repeat(depth);
|
|
52
|
-
for (const [i, edge] of edges.entries()) {
|
|
53
|
-
if (i === 0) {
|
|
54
|
-
lines.push(`${indent}:hasEdge [`);
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
lines.push(`${indent}] , [`);
|
|
58
|
-
}
|
|
59
|
-
writeEdge(lines, edge, depth + 1);
|
|
60
|
-
}
|
|
61
|
-
lines.push(`${indent}]`);
|
|
62
|
-
}
|
|
63
|
-
function writeEdge(lines, edge, depth) {
|
|
64
|
-
const indent = INDENT.repeat(depth);
|
|
65
|
-
lines.push(`${indent}a :Edge ;`);
|
|
66
|
-
if (isSwitch(edge.target)) {
|
|
67
|
-
lines.push(`${indent}:edgeSwitch [`);
|
|
68
|
-
writeSwitch(lines, edge.target, depth + 1);
|
|
69
|
-
lines.push(`${indent}] ;`);
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
lines.push(`${indent}:edgeTarget [`);
|
|
73
|
-
writeNode(lines, edge.target, depth + 1);
|
|
74
|
-
lines.push(`${indent}] ;`);
|
|
75
|
-
}
|
|
76
|
-
writeRelation(lines, edge, depth);
|
|
77
|
-
}
|
|
78
|
-
function writeSwitch(lines, sw, depth) {
|
|
79
|
-
const indent = INDENT.repeat(depth);
|
|
80
|
-
lines.push(`${indent}a :Switch ;`);
|
|
81
|
-
lines.push(`${indent}:discriminator "${sw.discriminator}" ;`);
|
|
82
|
-
for (const [i, sc] of sw.cases.entries()) {
|
|
83
|
-
if (i === 0) {
|
|
84
|
-
lines.push(`${indent}:hasCase [`);
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
lines.push(`${indent}] , [`);
|
|
88
|
-
}
|
|
89
|
-
writeSwitchCase(lines, sc, depth + 1);
|
|
90
|
-
}
|
|
91
|
-
lines.push(`${indent}]`);
|
|
92
|
-
}
|
|
93
|
-
function writeSwitchCase(lines, sc, depth) {
|
|
94
|
-
const indent = INDENT.repeat(depth);
|
|
95
|
-
lines.push(`${indent}a :SwitchCase ;`);
|
|
96
|
-
lines.push(`${indent}:caseNode [`);
|
|
97
|
-
writeNode(lines, sc.node, depth + 1);
|
|
98
|
-
lines.push(`${indent}]`);
|
|
99
|
-
}
|
|
100
|
-
function writeRelation(lines, edge, depth) {
|
|
101
|
-
const indent = INDENT.repeat(depth);
|
|
102
|
-
lines.push(`${indent}:hasRelation [`);
|
|
103
|
-
const inner = INDENT.repeat(depth + 1);
|
|
104
|
-
lines.push(`${inner}a :Relation ;`);
|
|
105
|
-
if (edge.relation.slotName) {
|
|
106
|
-
lines.push(`${inner}:cardinality "${edge.relation.cardinality}" ;`);
|
|
107
|
-
lines.push(`${inner}:slotName "${edge.relation.slotName}"`);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
lines.push(`${inner}:cardinality "${edge.relation.cardinality}"`);
|
|
111
|
-
}
|
|
112
|
-
lines.push(`${indent}]`);
|
|
113
|
-
}
|
|
114
|
-
function isSwitch(target) {
|
|
115
|
-
return "discriminator" in target;
|
|
116
|
-
}
|
package/dist/esm/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
package/dist/parse.d.ts
DELETED