@canonical/pragma-cli 0.35.0 → 0.37.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 +2 -2
- package/bundled-skills/add-standard/SKILL.md +338 -0
- package/bundled-skills/adoption-a1-styles/SKILL.md +269 -0
- package/bundled-skills/adoption-a2-components/SKILL.md +291 -0
- package/bundled-skills/adoption-a3-forms/SKILL.md +260 -0
- package/bundled-skills/anatomy-author/ANATOMY_DSL_SPEC.md +406 -0
- package/bundled-skills/anatomy-author/SKILL.md +1226 -0
- package/bundled-skills/design-auditor/SKILL.md +455 -0
- package/bundled-skills/implement-component/SKILL.md +333 -0
- package/bundled-skills/specify-component/SKILL.md +331 -0
- package/bundled-skills/specify-pattern/SKILL.md +292 -0
- package/dist/package.json +24 -20
- package/dist/pragma.conf.js +266 -34
- package/dist/pragma.conf.js.map +1 -1
- package/dist/src/bin.js +1 -1
- package/dist/src/bin.js.map +1 -1
- package/dist/src/capabilities/capabilities/hints.js +1 -1
- package/dist/src/capabilities/capabilities/hints.js.map +1 -1
- package/dist/src/capabilities/colophon/colophon.render.js +1 -1
- package/dist/src/capabilities/colophon/colophon.render.js.map +1 -1
- package/dist/src/capabilities/create/create.verb.js +2 -1
- package/dist/src/capabilities/create/create.verb.js.map +1 -1
- package/dist/src/capabilities/create/createSurface.generated.js +23 -1
- package/dist/src/capabilities/create/createSurface.generated.js.map +1 -1
- package/dist/src/capabilities/create/mount.js +4 -3
- package/dist/src/capabilities/create/mount.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/checkNodeVersion.js +11 -6
- package/dist/src/capabilities/doctor/checks/checkNodeVersion.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/checkPackageRefs.js +60 -4
- package/dist/src/capabilities/doctor/checks/checkPackageRefs.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/checkShellCompletions.js +8 -8
- package/dist/src/capabilities/doctor/checks/checkShellCompletions.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/harnessInventory.js +195 -0
- package/dist/src/capabilities/doctor/checks/harnessInventory.js.map +1 -0
- package/dist/src/capabilities/doctor/checks/index.js +6 -6
- package/dist/src/capabilities/doctor/checks/isSupportedNodeVersion.js +38 -0
- package/dist/src/capabilities/doctor/checks/isSupportedNodeVersion.js.map +1 -0
- package/dist/src/capabilities/doctor/checks/targetHealth.js +194 -50
- package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
- package/dist/src/capabilities/doctor/doctor.render.js +43 -64
- package/dist/src/capabilities/doctor/doctor.render.js.map +1 -1
- package/dist/src/capabilities/doctor/doctor.verb.js +6 -2
- package/dist/src/capabilities/doctor/doctor.verb.js.map +1 -1
- package/dist/src/capabilities/doctor/runChecks.js +14 -11
- package/dist/src/capabilities/doctor/runChecks.js.map +1 -1
- package/dist/src/capabilities/graph/query.render.js +2 -2
- package/dist/src/capabilities/graph/query.render.js.map +1 -1
- package/dist/src/capabilities/info/collectInfo.js +8 -2
- package/dist/src/capabilities/info/collectInfo.js.map +1 -1
- package/dist/src/capabilities/info/info.render.js +6 -2
- package/dist/src/capabilities/info/info.render.js.map +1 -1
- package/dist/src/capabilities/prompt/prompt.render.js +2 -2
- package/dist/src/capabilities/prompt/prompt.render.js.map +1 -1
- package/dist/src/capabilities/setup/buildPlan.js +43 -39
- package/dist/src/capabilities/setup/buildPlan.js.map +1 -1
- package/dist/src/capabilities/setup/mode.js +2 -2
- package/dist/src/capabilities/setup/operations/index.js +4 -4
- package/dist/src/capabilities/setup/operations/index.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupCompletions.js +6 -2
- package/dist/src/capabilities/setup/operations/setupCompletions.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupConfig.js +4 -2
- package/dist/src/capabilities/setup/operations/setupConfig.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupGenerator.js +156 -58
- package/dist/src/capabilities/setup/operations/setupGenerator.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupLsp.js +136 -38
- package/dist/src/capabilities/setup/operations/setupLsp.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupMcp.js +101 -52
- package/dist/src/capabilities/setup/operations/setupMcp.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupSkills.js +329 -49
- package/dist/src/capabilities/setup/operations/setupSkills.js.map +1 -1
- package/dist/src/capabilities/setup/plan.js.map +1 -1
- package/dist/src/capabilities/setup/plan.render.js +144 -66
- package/dist/src/capabilities/setup/plan.render.js.map +1 -1
- package/dist/src/capabilities/setup/setup.render.js +1 -1
- package/dist/src/capabilities/setup/setup.verb.js +165 -63
- package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
- package/dist/src/capabilities/setup/targets.js +122 -51
- package/dist/src/capabilities/setup/targets.js.map +1 -1
- package/dist/src/capabilities/shared/index.js +7 -6
- package/dist/src/capabilities/shared/index.js.map +1 -1
- package/dist/src/capabilities/shared/packageManager.js +300 -54
- package/dist/src/capabilities/shared/packageManager.js.map +1 -1
- package/dist/src/capabilities/skill/discover.js +97 -11
- package/dist/src/capabilities/skill/discover.js.map +1 -1
- package/dist/src/capabilities/skill/render.js +2 -2
- package/dist/src/capabilities/skill/render.js.map +1 -1
- package/dist/src/capabilities/sources/installSkills.js +145 -3
- package/dist/src/capabilities/sources/installSkills.js.map +1 -1
- package/dist/src/capabilities/sources/runUpdate.js +68 -2
- package/dist/src/capabilities/sources/runUpdate.js.map +1 -1
- package/dist/src/capabilities/sources/update.verb.js +3 -3
- package/dist/src/capabilities/sources/update.verb.js.map +1 -1
- package/dist/src/capabilities/upgrade/runUpgrade.js +43 -7
- package/dist/src/capabilities/upgrade/runUpgrade.js.map +1 -1
- package/dist/src/capabilities/upgrade/upgrade.render.js +10 -2
- package/dist/src/capabilities/upgrade/upgrade.render.js.map +1 -1
- package/dist/src/constants.js +13 -2
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernel/index.js +11 -2
- package/dist/src/kernel/index.js.map +1 -1
- package/dist/src/kernel/interactivity.js +68 -0
- package/dist/src/kernel/interactivity.js.map +1 -0
- package/dist/src/kernel/packs/renderPack.js +3 -3
- package/dist/src/kernel/packs/renderPack.js.map +1 -1
- package/dist/src/kernel/packs/resolveEntity.js +63 -12
- package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
- package/dist/src/kernel/packs/runBodies.js +57 -4
- package/dist/src/kernel/packs/runBodies.js.map +1 -1
- package/dist/src/kernel/packs/schema.js +54 -2
- package/dist/src/kernel/packs/schema.js.map +1 -1
- package/dist/src/kernel/packs/sparql/applyFilters.js +104 -5
- package/dist/src/kernel/packs/sparql/applyFilters.js.map +1 -1
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js +310 -43
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
- package/dist/src/kernel/packs/types.js.map +1 -1
- package/dist/src/kernel/project/cli/buildProgram.js +1 -1
- package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
- package/dist/src/kernel/project/cli/dispatch.js +46 -24
- package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
- package/dist/src/kernel/project/cli/globalFlags.js +4 -1
- package/dist/src/kernel/project/cli/globalFlags.js.map +1 -1
- package/dist/src/kernel/project/cli/helpFormat.js +1 -2
- package/dist/src/kernel/project/cli/helpFormat.js.map +1 -1
- package/dist/src/kernel/project/cli/rootHelp.js +42 -9
- package/dist/src/kernel/project/cli/rootHelp.js.map +1 -1
- package/dist/src/kernel/project/mcp/registerVerb.js +16 -1
- package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
- package/dist/src/kernel/render/renderers.js +1 -1
- package/dist/src/kernel/render/style.js +29 -9
- package/dist/src/kernel/render/style.js.map +1 -1
- package/dist/src/kernel/render/vocabulary.js +174 -0
- package/dist/src/kernel/render/vocabulary.js.map +1 -0
- package/dist/src/kernel/runtime/graphpack/embedded/pack.generated.js +2 -3
- package/dist/src/kernel/runtime/graphpack/embedded/pack.generated.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/embedded/pack.index.generated.js +1 -1
- package/dist/src/kernel/runtime/graphpack/embedded/pack.index.generated.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.js +4 -0
- package/dist/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.js.map +1 -0
- package/dist/src/kernel/runtime/graphpack/embedded.js +13 -6
- package/dist/src/kernel/runtime/graphpack/embedded.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/read.js +14 -9
- package/dist/src/kernel/runtime/graphpack/read.js.map +1 -1
- package/dist/src/kernel/runtime/loadSession.js +3 -1
- package/dist/src/kernel/runtime/loadSession.js.map +1 -1
- package/dist/src/kernel/runtime/probe.js +1 -1
- package/dist/src/kernel/runtime/probe.js.map +1 -1
- package/dist/src/kernel/runtime/refs/parseRef.js +17 -1
- package/dist/src/kernel/runtime/refs/parseRef.js.map +1 -1
- package/dist/src/kernel/runtime/refs/resolve.js +9 -3
- package/dist/src/kernel/runtime/refs/resolve.js.map +1 -1
- package/dist/src/kernel/spec/emitReference.js +1 -1
- package/dist/src/kernel/spec/emitReference.js.map +1 -1
- package/package.json +24 -20
- package/pragma.conf.ts +272 -34
- package/src/bin.ts +8 -1
- package/src/capabilities/block.parity.test.ts +25 -11
- package/src/capabilities/block.shipped.exec.test.ts +282 -0
- package/src/capabilities/block.tierRank.exec.test.ts +300 -0
- package/src/capabilities/capabilities/hints.ts +1 -1
- package/src/capabilities/colophon/colophon.render.ts +1 -2
- package/src/capabilities/colophon/colophon.test.ts +2 -2
- package/src/capabilities/config/collectConfigShow.test.ts +1 -0
- package/src/capabilities/create/byteEquality.test.ts +28 -1
- package/src/capabilities/create/create.test.ts +1 -0
- package/src/capabilities/create/create.verb.ts +2 -1
- package/src/capabilities/create/createGrammar.test.ts +5 -2
- package/src/capabilities/create/createSurface.generated.ts +23 -1
- package/src/capabilities/create/crossCli.subprocess.test.ts +10 -3
- package/src/capabilities/create/mount.ts +3 -3
- package/src/capabilities/distribution.parity.test.ts +4 -0
- package/src/capabilities/doctor/checks/checkNodeVersion.test.ts +49 -0
- package/src/capabilities/doctor/checks/checkNodeVersion.ts +11 -7
- package/src/capabilities/doctor/checks/checkPackageRefs.ts +69 -4
- package/src/capabilities/doctor/checks/checkShellCompletions.test.ts +6 -4
- package/src/capabilities/doctor/checks/checkShellCompletions.ts +8 -8
- package/src/capabilities/doctor/checks/harnessInventory.test.ts +219 -0
- package/src/capabilities/doctor/checks/harnessInventory.ts +298 -0
- package/src/capabilities/doctor/checks/index.ts +6 -6
- package/src/capabilities/doctor/checks/isSupportedNodeVersion.test.ts +111 -0
- package/src/capabilities/doctor/checks/isSupportedNodeVersion.ts +34 -0
- package/src/capabilities/doctor/checks/mcpCommand.test.ts +7 -1
- package/src/capabilities/doctor/checks/targetHealth.ts +229 -59
- package/src/capabilities/doctor/doctor.render.test.ts +108 -32
- package/src/capabilities/doctor/doctor.render.ts +56 -80
- package/src/capabilities/doctor/doctor.test.ts +247 -35
- package/src/capabilities/doctor/doctor.verb.ts +7 -2
- package/src/capabilities/doctor/runChecks.ts +14 -11
- package/src/capabilities/doctor/types.ts +15 -24
- package/src/capabilities/emptyRecovery.test.ts +10 -2
- package/src/capabilities/graph/query.render.ts +2 -2
- package/src/capabilities/info/collectInfo.ts +8 -1
- package/src/capabilities/info/info.render.ts +6 -2
- package/src/capabilities/info/info.test.ts +37 -1
- package/src/capabilities/info/types.ts +10 -2
- package/src/capabilities/lazy.test.ts +26 -2
- package/src/capabilities/listLookup.shipped.exec.test.ts +340 -0
- package/src/capabilities/prompt/prompt.render.ts +2 -2
- package/src/capabilities/renderVocabularySync.test.ts +82 -0
- package/src/capabilities/resources/resources.test.ts +38 -2
- package/src/capabilities/scopeTypeSync.test.ts +29 -15
- package/src/capabilities/setup/buildPlan.ts +45 -41
- package/src/capabilities/setup/index.ts +1 -1
- package/src/capabilities/setup/mode.ts +2 -2
- package/src/capabilities/setup/operations/index.ts +6 -1
- package/src/capabilities/setup/operations/setupCompletions.ts +9 -2
- package/src/capabilities/setup/operations/setupConfig.ts +7 -2
- package/src/capabilities/setup/operations/setupGenerator.ts +227 -84
- package/src/capabilities/setup/operations/setupLsp.ts +203 -38
- package/src/capabilities/setup/operations/setupMcp.ts +139 -62
- package/src/capabilities/setup/operations/setupSkills.ts +399 -60
- package/src/capabilities/setup/plan.render.ts +171 -76
- package/src/capabilities/setup/plan.ts +17 -12
- package/src/capabilities/setup/setup.mcp.correctness.test.ts +9 -9
- package/src/capabilities/setup/setup.render.test.ts +50 -36
- package/src/capabilities/setup/setup.render.ts +1 -1
- package/src/capabilities/setup/setup.test.ts +1126 -50
- package/src/capabilities/setup/setup.verb.ts +174 -68
- package/src/capabilities/setup/targets.ts +138 -60
- package/src/capabilities/setup/types.ts +10 -18
- package/src/capabilities/shared/index.ts +18 -6
- package/src/capabilities/shared/packageManager.test.ts +421 -6
- package/src/capabilities/shared/packageManager.ts +394 -59
- package/src/capabilities/skill/bundledSkills.test.ts +347 -0
- package/src/capabilities/skill/discover.ts +100 -11
- package/src/capabilities/skill/render.ts +2 -2
- package/src/capabilities/skill/skill.test.ts +17 -4
- package/src/capabilities/sources/installSkills.ts +181 -3
- package/src/capabilities/sources/runUpdate.ts +78 -2
- package/src/capabilities/sources/sources.test.ts +228 -0
- package/src/capabilities/sources/update.verb.ts +3 -3
- package/src/capabilities/surface.test.ts +14 -6
- package/src/capabilities/upgrade/runUpgrade.ts +45 -6
- package/src/capabilities/upgrade/types.ts +10 -2
- package/src/capabilities/upgrade/upgrade.render.ts +9 -2
- package/src/capabilities/upgrade/upgrade.test.ts +72 -0
- package/src/constants.ts +14 -1
- package/src/identity.test.ts +18 -5
- package/src/kernel/completion/entitySource.test.ts +15 -2
- package/src/kernel/completion/safety.test.ts +16 -9
- package/src/kernel/config/defaults.test.ts +19 -3
- package/src/kernel/config/readConfig.test.ts +1 -1
- package/src/kernel/index.ts +11 -2
- package/src/kernel/interactivity.test.ts +76 -0
- package/src/kernel/interactivity.ts +69 -0
- package/src/kernel/packs/compile.test.ts +92 -0
- package/src/kernel/packs/renderPack.ts +3 -3
- package/src/kernel/packs/resolveEntity.test.ts +75 -14
- package/src/kernel/packs/resolveEntity.ts +88 -24
- package/src/kernel/packs/runBodies.ts +84 -19
- package/src/kernel/packs/schema.ts +60 -4
- package/src/kernel/packs/sparql/applyFilters.ts +125 -4
- package/src/kernel/packs/sparql/buildLookupQuery.test.ts +290 -0
- package/src/kernel/packs/sparql/buildLookupQuery.ts +327 -45
- package/src/kernel/packs/toolDescription.test.ts +35 -1
- package/src/kernel/packs/types.ts +125 -2
- package/src/kernel/project/cli/buildProgram.test.ts +73 -2
- package/src/kernel/project/cli/buildProgram.ts +8 -1
- package/src/kernel/project/cli/dispatch.test.ts +5 -4
- package/src/kernel/project/cli/dispatch.ts +48 -25
- package/src/kernel/project/cli/globalFlags.ts +4 -1
- package/src/kernel/project/cli/helpFormat.ts +1 -2
- package/src/kernel/project/cli/rootHelp.ts +44 -8
- package/src/kernel/project/mcp/registerVerb.ts +20 -1
- package/src/kernel/render/prefixes.test.ts +2 -0
- package/src/kernel/render/renderers.ts +1 -1
- package/src/kernel/render/style.ts +32 -9
- package/src/kernel/render/vocabulary.ts +276 -0
- package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +2 -3
- package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +1 -1
- package/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.ts +3 -0
- package/src/kernel/runtime/graphpack/embedded.ts +14 -6
- package/src/kernel/runtime/graphpack/graphpack.test.ts +31 -5
- package/src/kernel/runtime/graphpack/read.ts +14 -12
- package/src/kernel/runtime/loadSession.ts +3 -1
- package/src/kernel/runtime/probe.ts +1 -1
- package/src/kernel/runtime/refs/parseRef.test.ts +49 -1
- package/src/kernel/runtime/refs/parseRef.ts +25 -1
- package/src/kernel/runtime/refs/resolve.ts +9 -3
- package/src/kernel/runtime/types.ts +17 -0
- package/src/kernel/spec/emitReference.ts +1 -1
- package/src/kernel/spec/types.ts +35 -6
- package/src/testing/PARITY_GAPS.ts +9 -3
- package/src/testing/behavioral/docExamples.test.ts +4 -2
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +110 -7
- package/src/testing/behavioral/journeys.firstInstall.test.ts +7 -2
- package/src/testing/behavioral/journeys.packageStories.test.ts +6 -3
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +26 -1
- package/src/testing/eval/cases/readNouns.ts +245 -9
- package/src/testing/fixtures/blockGraph.ts +28 -13
- package/src/testing/fixtures/graph/canonical.ts +95 -12
- package/src/testing/helpers/runCli.test.ts +44 -0
- package/src/testing/helpers/runCli.ts +27 -3
- package/dist/src/capabilities/shared/bands.js +0 -16
- package/dist/src/capabilities/shared/bands.js.map +0 -1
- package/src/capabilities/shared/bands.ts +0 -16
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# Anatomy DSL Specification
|
|
2
|
+
|
|
3
|
+
This specification presents a DSL to represent design system anatomies, providing an accurate platform-agnostic markup primitive to precede implementation.
|
|
4
|
+
|
|
5
|
+
## Rationale
|
|
6
|
+
|
|
7
|
+
Design systems need a formal way to describe component structure that:
|
|
8
|
+
- Precedes and guides implementation
|
|
9
|
+
- Is platform-agnostic (works for React, SwiftUI, Flutter, etc.)
|
|
10
|
+
- Supports discussion and review
|
|
11
|
+
- Enables automated tooling (auditing, code generation)
|
|
12
|
+
|
|
13
|
+
## Intended Usage
|
|
14
|
+
|
|
15
|
+
1. **Documentation**: Implementation primitive for markup and style bindings
|
|
16
|
+
2. **Specification**: Using the tree-based DSL to identify entities to implement and/or reuse
|
|
17
|
+
3. **Discussion**: Using the DSL to discuss across conversations related to DS (e.g., "I believe these nodes should be siblings, not parents of one another")
|
|
18
|
+
4. **Inference**: Supporting automated inference to audit a codebase against its specifications or to support code generation
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
### General DSL Requirements
|
|
23
|
+
|
|
24
|
+
- The DSL MUST optimize for readability
|
|
25
|
+
- The DSL MUST be easy to get started with and use a familiar language
|
|
26
|
+
- The scope of the DSL MUST be minimized to cover only the strict necessary - additional specification information being covered in the schema
|
|
27
|
+
|
|
28
|
+
### Modelling Requirements
|
|
29
|
+
|
|
30
|
+
- The children of a node MUST be modelled through a reified relation for annotation purposes
|
|
31
|
+
- The DSL MUST support anonymous nodes (nodes that are not named components, for instance an unnamed "div"). In this case, the DSL should support role annotations
|
|
32
|
+
- The DSL MUST support reified annotations of cardinality
|
|
33
|
+
- The DSL MUST support all classes of UI Blocks identified in the ontology (Layout, Pattern, Component, Subcomponent, Group)
|
|
34
|
+
|
|
35
|
+
## Type System
|
|
36
|
+
|
|
37
|
+
We structure the children one-to-many relation following inspiration by [the Relay connection pattern](https://relay.dev/graphql/connections.htm) and propose the following typings.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
/* Reusable types */
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Styles use a CTI (Category-Type-Item) inspired flat key structure for
|
|
44
|
+
* platform-agnostic UI properties. This allows to avoid using language
|
|
45
|
+
* specific keys such as CSS.
|
|
46
|
+
*
|
|
47
|
+
* KEY NAMING CONVENTION:
|
|
48
|
+
* Properties follow a dot-notation pattern: "category.type[.item]"
|
|
49
|
+
* - Category: Primary concern (layout, spacing, appearance, typography, size, etc.)
|
|
50
|
+
* - Type: Specific aspect within that category
|
|
51
|
+
* - Item: Optional further specification
|
|
52
|
+
*
|
|
53
|
+
* INVARIANT VS THEMEABLE:
|
|
54
|
+
* Whether a property is invariant (structural) or themeable depends on its
|
|
55
|
+
* semantic meaning and value type, rather than strict rules:
|
|
56
|
+
*
|
|
57
|
+
* Typically invariant (structural decisions):
|
|
58
|
+
* - layout.type: "stack" | "flow" | "grid" // Component structure
|
|
59
|
+
* - layout.direction: "horizontal" | "vertical"
|
|
60
|
+
* - size.width: "fill" | "hug" | "100%" // Structural sizing
|
|
61
|
+
*
|
|
62
|
+
* Typically themeable (brand/theme variations):
|
|
63
|
+
* - appearance.*: Color, shadow, radius values via tokens
|
|
64
|
+
* - spacing.*: When referencing design tokens
|
|
65
|
+
* - typography.*: Font properties via tokens
|
|
66
|
+
*
|
|
67
|
+
* Context-dependent:
|
|
68
|
+
* - size.width: "320px" or "size/card/width" // Token = themeable
|
|
69
|
+
* - size.width: "fill" or "100%" // Structural = invariant
|
|
70
|
+
* - spacing.internal: "16" // Fixed value = invariant
|
|
71
|
+
* - spacing.internal: "spacing/medium" // Token = themeable
|
|
72
|
+
*
|
|
73
|
+
* The distinction is semantic: does this property define structure or appearance?
|
|
74
|
+
*/
|
|
75
|
+
type Styles = Record<string, TokenPath | TokenPath[] | PrimitiveValue>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* TokenPath represents a forward-slash delimited path to a design token.
|
|
79
|
+
* Follows design token naming conventions referenced by the W3C Design Token Format.
|
|
80
|
+
*
|
|
81
|
+
* Examples:
|
|
82
|
+
* - "spacing/medium"
|
|
83
|
+
* - "color/surface/primary"
|
|
84
|
+
* - "font/size/heading/1"
|
|
85
|
+
* - "border/width/thin"
|
|
86
|
+
* - "shadow/elevated/medium"
|
|
87
|
+
* - "radius/button/default"
|
|
88
|
+
*
|
|
89
|
+
* Token paths are resolved at runtime against the active theme.
|
|
90
|
+
*/
|
|
91
|
+
type TokenPath = string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* PrimitiveValue represents direct values not resolved from tokens.
|
|
95
|
+
* Used for structural decisions and fixed values.
|
|
96
|
+
*
|
|
97
|
+
* Examples:
|
|
98
|
+
* - string: "stack", "flow", "center", "fill", "100%", "1fr"
|
|
99
|
+
* - number: 1.5 (aspect ratio), 2 (column count), -1 (z-index)
|
|
100
|
+
* - boolean: true/false (for wrap, reverse, etc.)
|
|
101
|
+
*/
|
|
102
|
+
type PrimitiveValue = string | number | boolean;
|
|
103
|
+
|
|
104
|
+
/* Main types */
|
|
105
|
+
|
|
106
|
+
interface Relation {
|
|
107
|
+
/**
|
|
108
|
+
* Cardinality represents the number of allowed instances of the related node.
|
|
109
|
+
* See https://en.wikipedia.org/wiki/Cardinality_(data_modeling) for reference.
|
|
110
|
+
*
|
|
111
|
+
* Examples:
|
|
112
|
+
* - "1" : Exactly one (required)
|
|
113
|
+
* - "0..1" : Zero or one (optional)
|
|
114
|
+
* - "0..*" : Zero or more
|
|
115
|
+
* - "1..*" : One or more
|
|
116
|
+
* - "2..5" : Between 2 and 5
|
|
117
|
+
*/
|
|
118
|
+
cardinality: string;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Maps content to a specific slot in the parent component.
|
|
122
|
+
*
|
|
123
|
+
* Common values:
|
|
124
|
+
* - "default" : Main content (React children)
|
|
125
|
+
* - "header" : Header slot
|
|
126
|
+
* - "footer" : Footer slot
|
|
127
|
+
* - "icon" : Icon placement
|
|
128
|
+
* - "label" : Text label
|
|
129
|
+
* - Custom slots as needed
|
|
130
|
+
*/
|
|
131
|
+
slotName?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Base interface for all nodes in the anatomy tree.
|
|
136
|
+
*/
|
|
137
|
+
interface BaseNode {
|
|
138
|
+
/**
|
|
139
|
+
* Style properties using CTI-inspired keys.
|
|
140
|
+
*
|
|
141
|
+
* Common patterns and their platform mappings:
|
|
142
|
+
*
|
|
143
|
+
* LAYOUT:
|
|
144
|
+
* - "layout.type": "stack" | "flow" | "grid"
|
|
145
|
+
* -> CSS: display + flexDirection | SwiftUI: VStack/HStack | Flutter: Column/Row
|
|
146
|
+
* - "layout.align": "center" | "start" | "end"
|
|
147
|
+
* -> CSS: align-items | SwiftUI: alignment | Flutter: crossAxisAlignment
|
|
148
|
+
*
|
|
149
|
+
* SPACING:
|
|
150
|
+
* - "spacing.internal": "spacing/medium"
|
|
151
|
+
* -> CSS: padding | SwiftUI: .padding() | Flutter: EdgeInsets
|
|
152
|
+
* - "spacing.external": "spacing/large"
|
|
153
|
+
* -> CSS: margin | SwiftUI: frame modifiers | Flutter: Container margin
|
|
154
|
+
* - "spacing.gap": "spacing/small"
|
|
155
|
+
* -> CSS: gap | SwiftUI: spacing parameter | Flutter: SizedBox between
|
|
156
|
+
*
|
|
157
|
+
* APPEARANCE:
|
|
158
|
+
* - "appearance.background": "color/surface/primary"
|
|
159
|
+
* -> CSS: background | SwiftUI: .background() | Flutter: Container color
|
|
160
|
+
* - "appearance.radius": "radius/medium"
|
|
161
|
+
* -> CSS: border-radius | SwiftUI: .cornerRadius() | Flutter: BorderRadius
|
|
162
|
+
*
|
|
163
|
+
* SIZE:
|
|
164
|
+
* - "size.width": "fill" | "hug" | "size/card/width"
|
|
165
|
+
* -> CSS: width: 100% | auto | var() | SwiftUI: .frame() | Flutter: constraints
|
|
166
|
+
*
|
|
167
|
+
* Examples showing invariant vs themeable:
|
|
168
|
+
* {
|
|
169
|
+
* "layout.type": "grid", // Invariant: structural
|
|
170
|
+
* "layout.columns": "1fr 300px 1fr", // Invariant: grid structure
|
|
171
|
+
* "spacing.gap": "spacing/grid/gap", // Themeable: token reference
|
|
172
|
+
* "appearance.background": "color/surface", // Themeable: always
|
|
173
|
+
* "size.width": "fill", // Invariant: structural behavior
|
|
174
|
+
* "size.max.width": "size/container/max", // Themeable: token reference
|
|
175
|
+
* "typography.align": "center", // Invariant: structural
|
|
176
|
+
* "typography.size": "font/size/body", // Themeable: token reference
|
|
177
|
+
* }
|
|
178
|
+
*/
|
|
179
|
+
styles?: Styles;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Child nodes and their relationships.
|
|
183
|
+
* Enables recursive component composition.
|
|
184
|
+
*/
|
|
185
|
+
edges?: Edge[];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Named nodes represent identifiable components in the design system.
|
|
190
|
+
*/
|
|
191
|
+
interface NamedNode extends BaseNode {
|
|
192
|
+
/**
|
|
193
|
+
* Unique identifier following "tier.type.name" pattern.
|
|
194
|
+
* Maps to URI field on UI Block in the ontology.
|
|
195
|
+
*
|
|
196
|
+
* Examples:
|
|
197
|
+
* - "global.component.button"
|
|
198
|
+
* - "global.component.card"
|
|
199
|
+
* - "apps.layout.application_layout"
|
|
200
|
+
*/
|
|
201
|
+
uri: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Anonymous nodes represent structural elements without DS identity.
|
|
206
|
+
*/
|
|
207
|
+
interface AnonymousNode extends BaseNode {
|
|
208
|
+
/**
|
|
209
|
+
* Human-readable description of the node's purpose.
|
|
210
|
+
*
|
|
211
|
+
* Examples:
|
|
212
|
+
* - "content wrapper"
|
|
213
|
+
* - "spacer element"
|
|
214
|
+
* - "icon container"
|
|
215
|
+
* - "layout grid cell"
|
|
216
|
+
*/
|
|
217
|
+
role: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Union type for all possible nodes.
|
|
222
|
+
*/
|
|
223
|
+
type Node = NamedNode | AnonymousNode;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* A switch fills one position with ONE of several alternatives,
|
|
227
|
+
* making polymorphism explicit at the edge level.
|
|
228
|
+
* The discriminator says who chooses:
|
|
229
|
+
* - "props" : the consumer chooses via component props
|
|
230
|
+
* - "internal" : the component chooses from its own state
|
|
231
|
+
* - "override" : the consumer may replace the default with a custom component
|
|
232
|
+
*/
|
|
233
|
+
interface Switch {
|
|
234
|
+
on: "props" | "internal" | "override";
|
|
235
|
+
cases: SwitchCase[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* One switch alternative — exactly one of `uri` or `node`.
|
|
240
|
+
* `uri` is the shorthand for `node: { uri }`; use the full `node` form
|
|
241
|
+
* when the case carries styles or edges. The reserved URI `$custom`
|
|
242
|
+
* marks a case filled by a user-provided component.
|
|
243
|
+
*/
|
|
244
|
+
interface SwitchCase {
|
|
245
|
+
uri?: string;
|
|
246
|
+
node?: Node;
|
|
247
|
+
|
|
248
|
+
/** Marks the default case. */
|
|
249
|
+
default?: boolean;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Represents a parent-child relationship in the anatomy tree.
|
|
254
|
+
*/
|
|
255
|
+
interface Edge {
|
|
256
|
+
/** The child node (Named or Anonymous) — exactly one of `node` or `switch` */
|
|
257
|
+
node?: Node;
|
|
258
|
+
|
|
259
|
+
/** A polymorphic position (mutually exclusive with node) */
|
|
260
|
+
switch?: Switch;
|
|
261
|
+
|
|
262
|
+
/** Relationship metadata (cardinality, slot) */
|
|
263
|
+
relation: Relation;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Root specification for a component anatomy.
|
|
268
|
+
* The top-level node must always be Named.
|
|
269
|
+
*/
|
|
270
|
+
interface AnatomySpec {
|
|
271
|
+
node: NamedNode;
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Language Choice
|
|
276
|
+
|
|
277
|
+
We propose the use of YAML, a mature indentation-based configuration syntax based on scalars, maps and lists. The main contender we have considered aside from YAML was JSON, rejected for its verbosity. We have also rejected TOML (maps with difficulty deeply nested nodes), SDLang and KDL (promising markup syntaxes without wide adoption at present).
|
|
278
|
+
|
|
279
|
+
## Examples
|
|
280
|
+
|
|
281
|
+
### Accordion
|
|
282
|
+
|
|
283
|
+
```yaml
|
|
284
|
+
node:
|
|
285
|
+
uri: global.component.accordion
|
|
286
|
+
styles:
|
|
287
|
+
# Structural (implicitly invariant)
|
|
288
|
+
layout.type: stack
|
|
289
|
+
layout.direction: vertical
|
|
290
|
+
|
|
291
|
+
# Themeable
|
|
292
|
+
appearance.border: border/style/accordion
|
|
293
|
+
|
|
294
|
+
edges:
|
|
295
|
+
# The repeating child is NAMED — reference its URI only; its subtree
|
|
296
|
+
# lives in its own anatomy. The live Accordion does the same.
|
|
297
|
+
- node:
|
|
298
|
+
uri: global.subcomponent.accordion-item
|
|
299
|
+
relation:
|
|
300
|
+
cardinality: "1..*"
|
|
301
|
+
slotName: default
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
The child's own anatomy — a separate spec on `global.subcomponent.accordion-item`
|
|
305
|
+
(transcribed from the live block) — carries the subtree as anonymous roles:
|
|
306
|
+
|
|
307
|
+
```yaml
|
|
308
|
+
node:
|
|
309
|
+
uri: global.subcomponent.accordion-item
|
|
310
|
+
styles:
|
|
311
|
+
layout.type: stack
|
|
312
|
+
layout.direction: vertical
|
|
313
|
+
edges:
|
|
314
|
+
- node:
|
|
315
|
+
role: header tab
|
|
316
|
+
styles:
|
|
317
|
+
layout.type: flow
|
|
318
|
+
layout.direction: horizontal
|
|
319
|
+
layout.align: center
|
|
320
|
+
interaction.cursor: pointer
|
|
321
|
+
edges:
|
|
322
|
+
- node:
|
|
323
|
+
role: control
|
|
324
|
+
styles:
|
|
325
|
+
size.width: size/icon/small
|
|
326
|
+
size.height: size/icon/small
|
|
327
|
+
relation:
|
|
328
|
+
cardinality: "1"
|
|
329
|
+
- node:
|
|
330
|
+
role: heading
|
|
331
|
+
relation:
|
|
332
|
+
cardinality: "1"
|
|
333
|
+
slotName: default
|
|
334
|
+
relation:
|
|
335
|
+
cardinality: "1"
|
|
336
|
+
slotName: header
|
|
337
|
+
|
|
338
|
+
- node:
|
|
339
|
+
role: content panel
|
|
340
|
+
styles:
|
|
341
|
+
layout.overflow: hidden
|
|
342
|
+
relation:
|
|
343
|
+
cardinality: "1"
|
|
344
|
+
slotName: default
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Card
|
|
348
|
+
|
|
349
|
+
```yaml
|
|
350
|
+
node:
|
|
351
|
+
uri: global.component.card
|
|
352
|
+
styles:
|
|
353
|
+
# Structural (implicitly invariant)
|
|
354
|
+
layout.type: stack
|
|
355
|
+
layout.direction: vertical
|
|
356
|
+
|
|
357
|
+
# Themeable
|
|
358
|
+
appearance.background: color/surface/card
|
|
359
|
+
appearance.shadow: shadow/card
|
|
360
|
+
appearance.radius: shape/rounded/full
|
|
361
|
+
spacing.gap: spacing/small
|
|
362
|
+
|
|
363
|
+
edges:
|
|
364
|
+
# Named children reference their URI only (each carries its own styles
|
|
365
|
+
# in its own anatomy); anonymous nodes carry their styles inline. A
|
|
366
|
+
# named child may carry contextual style overrides — never a copy of
|
|
367
|
+
# its subtree. The live Card models it the same way.
|
|
368
|
+
- node:
|
|
369
|
+
uri: global.subcomponent.card-header
|
|
370
|
+
relation:
|
|
371
|
+
cardinality: "0..1"
|
|
372
|
+
slotName: header
|
|
373
|
+
|
|
374
|
+
- node:
|
|
375
|
+
uri: global.subcomponent.card-image
|
|
376
|
+
relation:
|
|
377
|
+
cardinality: "0..1"
|
|
378
|
+
slotName: media
|
|
379
|
+
|
|
380
|
+
- node:
|
|
381
|
+
uri: global.subcomponent.card-content
|
|
382
|
+
relation:
|
|
383
|
+
cardinality: "1..1"
|
|
384
|
+
slotName: default
|
|
385
|
+
|
|
386
|
+
- node:
|
|
387
|
+
uri: global.subcomponent.card-footer
|
|
388
|
+
relation:
|
|
389
|
+
cardinality: "0..1"
|
|
390
|
+
slotName: footer
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Further Work
|
|
394
|
+
|
|
395
|
+
The following features would require additional work to this specification:
|
|
396
|
+
|
|
397
|
+
- Representation of related nodes displayed in portals
|
|
398
|
+
- Representation of conditional display
|
|
399
|
+
- Inheritance reference for styles (e.g., "NetworkCard" inherits the styles from "Card")
|
|
400
|
+
|
|
401
|
+
## References
|
|
402
|
+
|
|
403
|
+
Two main references have supported our reflection:
|
|
404
|
+
|
|
405
|
+
1. The work of the [Open UI W3C Working Group](https://open-ui.org/), which takes interest in a code-based anatomy for their specifications ([Example](https://open-ui.org/components/accordion.explainer/))
|
|
406
|
+
2. The work of Nathan Curtis, exploring a similar syntax in his article "[Components as Data](https://medium.com/@nathanacurtis/components-as-data-2be178777f21)"
|