@canonical/pragma-cli 0.36.0 → 0.38.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 +3 -2
- package/bundled-skills/adoption-a1-styles/SKILL.md +24 -0
- package/bundled-skills/adoption-a2-components/SKILL.md +22 -6
- package/bundled-skills/anatomy-author/ANATOMY_DSL_SPEC.md +1397 -327
- package/bundled-skills/anatomy-author/SKILL.md +840 -137
- package/bundled-skills/design-auditor/SKILL.md +133 -9
- package/bundled-skills/implement-component/SKILL.md +192 -23
- package/bundled-skills/specify-component/SKILL.md +124 -12
- package/bundled-skills/specify-pattern/SKILL.md +47 -8
- package/dist/package.json +23 -20
- package/dist/pragma.conf.js +963 -40
- package/dist/pragma.conf.js.map +1 -1
- package/dist/src/capabilities/capabilities/catalog.js +14 -5
- package/dist/src/capabilities/capabilities/catalog.js.map +1 -1
- package/dist/src/capabilities/capabilities/hints.js +33 -5
- package/dist/src/capabilities/capabilities/hints.js.map +1 -1
- package/dist/src/capabilities/config/show.render.js +30 -2
- package/dist/src/capabilities/config/show.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/doctor/checks/checkNodeVersion.js +11 -6
- package/dist/src/capabilities/doctor/checks/checkNodeVersion.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/harnessInventory.js +1 -1
- package/dist/src/capabilities/doctor/checks/harnessInventory.js.map +1 -1
- 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 +104 -14
- package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
- package/dist/src/capabilities/graph/connect.render.js +101 -0
- package/dist/src/capabilities/graph/connect.render.js.map +1 -0
- package/dist/src/capabilities/graph/connect.types.js +21 -0
- package/dist/src/capabilities/graph/connect.types.js.map +1 -0
- package/dist/src/capabilities/graph/connect.verb.js +147 -0
- package/dist/src/capabilities/graph/connect.verb.js.map +1 -0
- package/dist/src/capabilities/graph/index.js +5 -3
- package/dist/src/capabilities/graph/index.js.map +1 -1
- package/dist/src/capabilities/graph/queryText.js +206 -0
- package/dist/src/capabilities/graph/queryText.js.map +1 -0
- package/dist/src/capabilities/graph/relationIndex.js +302 -0
- package/dist/src/capabilities/graph/relationIndex.js.map +1 -0
- package/dist/src/capabilities/graph/runConnect.js +456 -0
- package/dist/src/capabilities/graph/runConnect.js.map +1 -0
- package/dist/src/capabilities/graph/runQuery.js +21 -4
- package/dist/src/capabilities/graph/runQuery.js.map +1 -1
- package/dist/src/capabilities/setup/buildPlan.js +6 -2
- package/dist/src/capabilities/setup/buildPlan.js.map +1 -1
- package/dist/src/capabilities/setup/operations/index.js +7 -2
- 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 +72 -14
- package/dist/src/capabilities/setup/operations/setupGenerator.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupLsp.js +372 -62
- package/dist/src/capabilities/setup/operations/setupLsp.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupMcp.js +150 -5
- package/dist/src/capabilities/setup/operations/setupMcp.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupSkills.js +4 -2
- package/dist/src/capabilities/setup/operations/setupSkills.js.map +1 -1
- package/dist/src/capabilities/setup/operations/writability.js +114 -0
- package/dist/src/capabilities/setup/operations/writability.js.map +1 -0
- package/dist/src/capabilities/setup/plan.js.map +1 -1
- package/dist/src/capabilities/setup/setup.verb.js +80 -31
- package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
- package/dist/src/capabilities/setup/targets.js +124 -42
- package/dist/src/capabilities/setup/targets.js.map +1 -1
- package/dist/src/capabilities/shared/index.js +1 -1
- package/dist/src/capabilities/shared/index.js.map +1 -1
- package/dist/src/constants.js +7 -1
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernel/error/renderError.js +3 -2
- package/dist/src/kernel/error/renderError.js.map +1 -1
- package/dist/src/kernel/error/validOptions.js +41 -0
- package/dist/src/kernel/error/validOptions.js.map +1 -0
- package/dist/src/kernel/packs/compile.js +90 -6
- package/dist/src/kernel/packs/compile.js.map +1 -1
- package/dist/src/kernel/packs/cursor.js +135 -0
- package/dist/src/kernel/packs/cursor.js.map +1 -0
- package/dist/src/kernel/packs/graphql/buildLookupDocument.js +9 -2
- package/dist/src/kernel/packs/graphql/buildLookupDocument.js.map +1 -1
- package/dist/src/kernel/packs/paging.js +108 -0
- package/dist/src/kernel/packs/paging.js.map +1 -0
- package/dist/src/kernel/packs/renderPack.js +154 -5
- package/dist/src/kernel/packs/renderPack.js.map +1 -1
- package/dist/src/kernel/packs/resolveEntity.js +118 -19
- package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
- package/dist/src/kernel/packs/runBodies.js +156 -18
- package/dist/src/kernel/packs/runBodies.js.map +1 -1
- package/dist/src/kernel/packs/schema.js +160 -12
- package/dist/src/kernel/packs/schema.js.map +1 -1
- package/dist/src/kernel/packs/sparql/authorQuery.js +227 -0
- package/dist/src/kernel/packs/sparql/authorQuery.js.map +1 -0
- package/dist/src/kernel/packs/sparql/buildListQuery.js +251 -0
- package/dist/src/kernel/packs/sparql/buildListQuery.js.map +1 -0
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js +125 -22
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
- package/dist/src/kernel/packs/sparql/filterValues.js +145 -0
- package/dist/src/kernel/packs/sparql/filterValues.js.map +1 -0
- package/dist/src/kernel/packs/sparql/index.js +24 -14
- package/dist/src/kernel/packs/sparql/index.js.map +1 -1
- package/dist/src/kernel/packs/sparql/runSelect.js +10 -4
- package/dist/src/kernel/packs/sparql/runSelect.js.map +1 -1
- package/dist/src/kernel/packs/sparql/searchTerm.js +25 -0
- package/dist/src/kernel/packs/sparql/searchTerm.js.map +1 -0
- package/dist/src/kernel/packs/storyRules.js +151 -0
- package/dist/src/kernel/packs/storyRules.js.map +1 -0
- package/dist/src/kernel/packs/tierScope.js +310 -0
- package/dist/src/kernel/packs/tierScope.js.map +1 -0
- package/dist/src/kernel/packs/types.js +80 -0
- package/dist/src/kernel/packs/types.js.map +1 -1
- package/dist/src/kernel/project/cli/buildProgram.js +10 -1
- package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
- package/dist/src/kernel/project/cli/dispatch.js +104 -3
- package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
- package/dist/src/kernel/project/cli/rootHelp.js +8 -5
- package/dist/src/kernel/project/cli/rootHelp.js.map +1 -1
- package/dist/src/kernel/project/cli/suggestNames.js +31 -7
- package/dist/src/kernel/project/cli/suggestNames.js.map +1 -1
- package/dist/src/kernel/project/mcp/registerVerb.js +5 -1
- package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
- package/dist/src/kernel/render/renderers.js +34 -2
- package/dist/src/kernel/render/renderers.js.map +1 -1
- 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 +17 -10
- 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/readEntity.js +19 -4
- package/dist/src/kernel/runtime/readEntity.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 +38 -5
- 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 +23 -20
- package/pragma.conf.ts +983 -40
- package/src/capabilities/block.parity.test.ts +207 -27
- package/src/capabilities/block.shipped.exec.test.ts +156 -14
- package/src/capabilities/block.tierRank.exec.test.ts +46 -9
- package/src/capabilities/capabilities/catalog.ts +14 -5
- package/src/capabilities/capabilities/hints.ts +40 -5
- package/src/capabilities/config/collectConfigShow.test.ts +1 -0
- package/src/capabilities/config/set.test.ts +24 -25
- package/src/capabilities/config/show.render.test.ts +9 -4
- package/src/capabilities/config/show.render.ts +30 -2
- 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 +4 -1
- package/src/capabilities/create/createSurface.generated.ts +23 -1
- package/src/capabilities/create/crossCli.subprocess.test.ts +10 -3
- package/src/capabilities/distribution.parity.test.ts +12 -11
- package/src/capabilities/distribution.test.ts +77 -7
- package/src/capabilities/doctor/checks/checkNodeVersion.test.ts +49 -0
- package/src/capabilities/doctor/checks/checkNodeVersion.ts +11 -7
- package/src/capabilities/doctor/checks/harnessInventory.test.ts +13 -6
- package/src/capabilities/doctor/checks/harnessInventory.ts +8 -4
- 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 +114 -13
- package/src/capabilities/doctor/doctor.test.ts +327 -36
- package/src/capabilities/emptyRecovery.test.ts +84 -28
- package/src/capabilities/graph/connect.render.ts +141 -0
- package/src/capabilities/graph/connect.shipped.exec.test.ts +370 -0
- package/src/capabilities/graph/connect.test.ts +361 -0
- package/src/capabilities/graph/connect.types.ts +136 -0
- package/src/capabilities/graph/connect.verb.ts +165 -0
- package/src/capabilities/graph/index.ts +5 -3
- package/src/capabilities/graph/query.shipped.exec.test.ts +66 -0
- package/src/capabilities/graph/query.test.ts +17 -0
- package/src/capabilities/graph/queryText.test.ts +121 -0
- package/src/capabilities/graph/queryText.ts +240 -0
- package/src/capabilities/graph/relationIndex.ts +372 -0
- package/src/capabilities/graph/runConnect.ts +577 -0
- package/src/capabilities/graph/runQuery.ts +21 -6
- package/src/capabilities/lazy.test.ts +32 -2
- package/src/capabilities/listBudget.shipped.exec.test.ts +239 -0
- package/src/capabilities/listLookup.shipped.exec.test.ts +387 -0
- package/src/capabilities/listQuery.shipped.exec.test.ts +400 -0
- package/src/capabilities/resources/resources.test.ts +38 -2
- package/src/capabilities/setup/buildPlan.ts +7 -1
- package/src/capabilities/setup/operations/index.ts +14 -0
- 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 +93 -15
- package/src/capabilities/setup/operations/setupLsp.ts +544 -85
- package/src/capabilities/setup/operations/setupMcp.ts +212 -4
- package/src/capabilities/setup/operations/setupSkills.ts +7 -2
- package/src/capabilities/setup/operations/writability.test.ts +151 -0
- package/src/capabilities/setup/operations/writability.ts +135 -0
- package/src/capabilities/setup/plan.ts +11 -0
- package/src/capabilities/setup/setup.test.ts +992 -16
- package/src/capabilities/setup/setup.verb.ts +84 -36
- package/src/capabilities/setup/targets.ts +152 -48
- package/src/capabilities/setup/types.ts +41 -5
- package/src/capabilities/shared/index.ts +1 -0
- package/src/capabilities/sources/sources.test.ts +55 -0
- package/src/capabilities/surface.test.ts +59 -11
- package/src/capabilities/tier.parity.test.ts +2 -2
- package/src/capabilities/token.parity.test.ts +784 -0
- package/src/capabilities/tokenGraph.cli.test.ts +279 -0
- package/src/capabilities/tokenGraph.shipped.exec.test.ts +653 -0
- package/src/capabilities/variable.parity.test.ts +448 -0
- package/src/constants.ts +8 -0
- package/src/kernel/completion/shellDrive.test.ts +32 -30
- package/src/kernel/config/defaults.test.ts +21 -2
- package/src/kernel/config/readConfig.test.ts +1 -1
- package/src/kernel/error/renderError.ts +3 -2
- package/src/kernel/error/validOptions.test.ts +57 -0
- package/src/kernel/error/validOptions.ts +45 -0
- package/src/kernel/packs/collect.test.ts +2 -0
- package/src/kernel/packs/compile.test.ts +188 -15
- package/src/kernel/packs/compile.ts +109 -14
- package/src/kernel/packs/cursor.ts +135 -0
- package/src/kernel/packs/filteredEmpty.test.ts +213 -0
- package/src/kernel/packs/graphql/buildLookupDocument.ts +16 -9
- package/src/kernel/packs/graphqlSource.test.ts +152 -0
- package/src/kernel/packs/listNotice.test.ts +156 -0
- package/src/kernel/packs/paging.ts +110 -0
- package/src/kernel/packs/renderPack.ts +186 -13
- package/src/kernel/packs/resolveEntity.test.ts +62 -3
- package/src/kernel/packs/resolveEntity.ts +186 -26
- package/src/kernel/packs/runBodies.ts +196 -26
- package/src/kernel/packs/schema.ts +180 -13
- package/src/kernel/packs/sparql/authorQuery.test.ts +179 -0
- package/src/kernel/packs/sparql/authorQuery.ts +257 -0
- package/src/kernel/packs/sparql/buildListQuery.test.ts +344 -0
- package/src/kernel/packs/sparql/buildListQuery.ts +344 -0
- package/src/kernel/packs/sparql/buildLookupQuery.test.ts +138 -0
- package/src/kernel/packs/sparql/buildLookupQuery.ts +140 -20
- package/src/kernel/packs/sparql/filterValues.test.ts +86 -0
- package/src/kernel/packs/sparql/filterValues.ts +182 -0
- package/src/kernel/packs/sparql/index.ts +30 -14
- package/src/kernel/packs/sparql/runSelect.test.ts +63 -0
- package/src/kernel/packs/sparql/runSelect.ts +42 -2
- package/src/kernel/packs/sparql/searchTerm.ts +29 -0
- package/src/kernel/packs/storyRules.ts +180 -0
- package/src/kernel/packs/tierScope.test.ts +487 -0
- package/src/kernel/packs/tierScope.ts +409 -0
- package/src/kernel/packs/toolDescription.test.ts +13 -10
- package/src/kernel/packs/types.ts +311 -9
- package/src/kernel/project/cli/buildProgram.ts +17 -1
- package/src/kernel/project/cli/dispatch.test.ts +87 -0
- package/src/kernel/project/cli/dispatch.ts +114 -4
- package/src/kernel/project/cli/rootHelp.ts +8 -5
- package/src/kernel/project/cli/suggest.test.ts +35 -0
- package/src/kernel/project/cli/suggestNames.ts +34 -7
- package/src/kernel/project/mcp/registerVerb.ts +5 -1
- package/src/kernel/render/contracts.ts +2 -0
- package/src/kernel/render/prefixes.test.ts +2 -0
- package/src/kernel/render/renderers.test.ts +43 -0
- package/src/kernel/render/renderers.ts +34 -1
- 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 +17 -13
- package/src/kernel/runtime/loadSession.ts +3 -1
- package/src/kernel/runtime/probe.ts +1 -1
- package/src/kernel/runtime/readEntity.ts +19 -4
- 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 +39 -5
- package/src/kernel/runtime/types.ts +30 -0
- package/src/kernel/spec/emitReference.ts +1 -1
- package/src/kernel/spec/surfaceConformance.test.ts +2 -2
- package/src/kernel/spec/types.ts +17 -0
- package/src/testing/PARITY_GAPS.ts +4 -4
- package/src/testing/behavioral/agentSession.mcp.test.ts +43 -39
- package/src/testing/behavioral/completion.test.ts +7 -6
- package/src/testing/behavioral/disclosure.test.ts +39 -37
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +82 -64
- package/src/testing/behavioral/errorMatrix.storeless.test.ts +11 -10
- package/src/testing/behavioral/journeys.cli.test.ts +71 -32
- package/src/testing/behavioral/journeys.defaultPack.test.ts +6 -4
- package/src/testing/behavioral/journeys.firstInstall.test.ts +70 -5
- package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +4 -3
- package/src/testing/behavioral/journeys.packageStories.test.ts +2 -1
- package/src/testing/behavioral/mcpSurface.test.ts +28 -25
- package/src/testing/behavioral/parity.test.ts +25 -23
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +20 -0
- package/src/testing/eval/cases/effectful.ts +7 -1
- package/src/testing/eval/cases/readNouns.ts +100 -11
- package/src/testing/fixtures/blockGraph.ts +89 -5
- package/src/testing/fixtures/connectGraph.ts +159 -0
- package/src/testing/fixtures/graph/canonical.ts +128 -32
- package/src/testing/helpers/fsProbe.ts +88 -0
- package/src/testing/helpers/runCli.test.ts +44 -0
- package/src/testing/helpers/runCli.ts +27 -3
- package/src/testing/perf/budgets.test.ts +3 -1
- package/src/testing/perf/budgets.ts +138 -54
- package/dist/src/kernel/packs/sparql/applyFilters.js +0 -167
- package/dist/src/kernel/packs/sparql/applyFilters.js.map +0 -1
- package/dist/src/kernel/packs/sparql/applySearch.js +0 -25
- package/dist/src/kernel/packs/sparql/applySearch.js.map +0 -1
- package/src/kernel/packs/sparql/applyFilters.ts +0 -203
- package/src/kernel/packs/sparql/applySearch.ts +0 -33
package/dist/pragma.conf.js
CHANGED
|
@@ -51,8 +51,10 @@ over GraphQL or raw SPARQL.
|
|
|
51
51
|
## How it fits together
|
|
52
52
|
|
|
53
53
|
- **Tiers** are a hierarchy (\`global\` > \`apps\` > \`apps/lxd\`): a lower tier
|
|
54
|
-
inherits and overrides the blocks of its ancestors, so scoping a
|
|
55
|
-
tier walks that chain.
|
|
54
|
+
inherits and overrides the blocks of its ancestors, so scoping a read to a
|
|
55
|
+
tier walks that chain. Reads of a tiered entity ARE scoped — a list answers
|
|
56
|
+
from the top-level tiers, \`--tier apps_lxd\` from that tier and its
|
|
57
|
+
ancestors, \`--tier all\` from every tier.
|
|
56
58
|
- **Channels** (\`normal\`, \`experimental\`, \`prerelease\`) gate visibility, so an
|
|
57
59
|
in-progress block never leaks into a stable answer.
|
|
58
60
|
|
|
@@ -67,7 +69,15 @@ by \`sources update\` and addressed by content hash, so the domain you query is
|
|
|
67
69
|
exactly the domain that was published.`;
|
|
68
70
|
/**
|
|
69
71
|
* The read stories the design-system pack supplies — `block`, `token`,
|
|
70
|
-
* `modifier` and `tier` as declared data rather than code.
|
|
72
|
+
* `variable`, `modifier` and `tier` as declared data rather than code.
|
|
73
|
+
*
|
|
74
|
+
* `token` and `variable` read the TOKEN-ONTOLOGY pack's four strata rather than
|
|
75
|
+
* this one's graph, and they are declared here anyway, deliberately: `token
|
|
76
|
+
* consumers` joins a symbol to the design-system records that consume it, so
|
|
77
|
+
* the pair spans both packs and there is no single pack whose `stories/*.json`
|
|
78
|
+
* could carry them. The day the strata are addressable without the design
|
|
79
|
+
* system — or the day either pack ships its own stories — is the day to split
|
|
80
|
+
* them out, and the note below about deletion applies to whichever half moves.
|
|
71
81
|
*
|
|
72
82
|
* The association with the pack is the point: when `@canonical/design-system`
|
|
73
83
|
* starts shipping its own `stories/*.json`, this block is deleted and the
|
|
@@ -77,11 +87,16 @@ exactly the domain that was published.`;
|
|
|
77
87
|
* layer does not know the pack grammar (`parsePackDefinition` does).
|
|
78
88
|
*/
|
|
79
89
|
const designSystemStories = [
|
|
80
|
-
// `block list` is declared content
|
|
81
|
-
//
|
|
82
|
-
// included, for everyone
|
|
83
|
-
//
|
|
84
|
-
//
|
|
90
|
+
// `block list` is declared content: one SELECT over the four UIBlock
|
|
91
|
+
// classes, listing every block the TIER SCOPE admits — experimental and
|
|
92
|
+
// alpha ones included, for everyone, since no read filters by channel.
|
|
93
|
+
//
|
|
94
|
+
// Tier filtering did come back in declared form, and in the form the story
|
|
95
|
+
// declares rather than the form the query text does: `tierScope` below names
|
|
96
|
+
// the hierarchy, and the kernel compiles the scope into this query as a
|
|
97
|
+
// constraint on `?uri` (`--tier all` for the unscoped list this used to be).
|
|
98
|
+
// The retired `--all-tiers` escape is not back — `--tier all` answers the
|
|
99
|
+
// same question with the argument a caller already holds. Display parity
|
|
85
100
|
// lives IN the query: `VALUES ?class` closes the type set, so the BINDs
|
|
86
101
|
// that derive `name` (declared name, else the IRI's local name), `type`
|
|
87
102
|
// (lowercased class local name), and `tier` (tier IRI's local name) operate
|
|
@@ -129,6 +144,30 @@ const designSystemStories = [
|
|
|
129
144
|
description: "List all design system blocks.",
|
|
130
145
|
toolDescription: "List all design system blocks with their type, tier, and modifier families. Use when browsing which blocks exist. Example: block_list {}.",
|
|
131
146
|
colophon: DESIGN_SYSTEM_COLOPHON,
|
|
147
|
+
// Blocks are TIERED, so every read of them is SCOPED: `block list` answers
|
|
148
|
+
// from the top-level tiers, `--tier apps_lxd` from that tier and its
|
|
149
|
+
// ancestors, `--tier all` from every tier (kernel/packs/tierScope.ts states
|
|
150
|
+
// the rule once, for every noun that declares this).
|
|
151
|
+
//
|
|
152
|
+
// The four terms are the ones the graph already carries, and three of them
|
|
153
|
+
// this story already declared for its RANKING (`scopeWeight` below): the
|
|
154
|
+
// hierarchy is the `/` in a tier's own `ds:name`, because the shipped graph
|
|
155
|
+
// asserts no parent edge to read instead — `ds:apps_lxd` is a `ds:Tier`
|
|
156
|
+
// with a name and nothing else. Reading the hierarchy from one place is
|
|
157
|
+
// what keeps the scope and the lookup ranking from disagreeing about which
|
|
158
|
+
// tier is above which.
|
|
159
|
+
//
|
|
160
|
+
// `base` is the editorial half, declared here for the reason `weights` is:
|
|
161
|
+
// nothing in the graph says `global` is the tier the others build on — the
|
|
162
|
+
// colophon above says it, and the 119 global blocks every product screen
|
|
163
|
+
// is assembled from say it. Without `base`, `--tier apps_lxd` would answer
|
|
164
|
+
// with LXD's nine blocks and hide the Buttons and Inputs they sit in.
|
|
165
|
+
tierScope: {
|
|
166
|
+
type: "ds:Tier",
|
|
167
|
+
via: "ds:tier",
|
|
168
|
+
by: "ds:name",
|
|
169
|
+
base: "ds:global",
|
|
170
|
+
},
|
|
132
171
|
list: {
|
|
133
172
|
query: [
|
|
134
173
|
"SELECT ?uri ?name ?type ?tier",
|
|
@@ -260,6 +299,10 @@ const designSystemStories = [
|
|
|
260
299
|
label: "Anatomy (DSL)",
|
|
261
300
|
kind: "code",
|
|
262
301
|
level: "detailed",
|
|
302
|
+
// The one piece of the notation that cannot be guessed from reading
|
|
303
|
+
// it: a bracketed value looks like a set of alternatives with no
|
|
304
|
+
// stated order of preference, and it is an ORDERED chain.
|
|
305
|
+
note: "A list value is the fallback chain the implementation reads, first wins.",
|
|
263
306
|
},
|
|
264
307
|
{
|
|
265
308
|
name: "anatomyClassic",
|
|
@@ -306,6 +349,69 @@ const designSystemStories = [
|
|
|
306
349
|
{ name: "uri", property: "ds:name", graphqlField: "uri" },
|
|
307
350
|
],
|
|
308
351
|
},
|
|
352
|
+
// Which symbols this block consumes, at which style key and rank — the
|
|
353
|
+
// mirror of `token consumers`, read from the block's end. It was
|
|
354
|
+
// DELIBERATELY ABSENT while none of the terms existed: the record the
|
|
355
|
+
// whole tuple hangs off is the design system's to mint, and until it
|
|
356
|
+
// did, `ds:hasTokenBinding`, `ds:consumesSymbol`, `ds:rank`,
|
|
357
|
+
// `ds:viaBlock` and `ds:node` were not declared properties at all. All
|
|
358
|
+
// five are now, with domains and ranges, and `ds:TokenBinding` is a
|
|
359
|
+
// class — so the declaration lands as the note then predicted, all six
|
|
360
|
+
// identity columns of it.
|
|
361
|
+
//
|
|
362
|
+
// SPARQL lane, and NOT this lookup's own GraphQL one, which is the only
|
|
363
|
+
// part of that prediction that had to change. Two of the six columns
|
|
364
|
+
// are unreachable through a generated document: `anatomy:styleKey` and
|
|
365
|
+
// `anatomy:styleState` carry no `rdfs:domain` — they are the anatomy
|
|
366
|
+
// vocabulary's, shared by every styled thing — so ke-graphql generates
|
|
367
|
+
// no field for them on `TokenBinding`, and a derived name the schema
|
|
368
|
+
// does not carry drops out of the document in silence. Measured on the
|
|
369
|
+
// shipped pack: Button rendered 24 rows with no key and no state, two
|
|
370
|
+
// of which (`spacing.internal.inline.start` and `…end`) were then
|
|
371
|
+
// byte-identical. A table whose rows a reader cannot tell apart is the
|
|
372
|
+
// defect this story refuses elsewhere, so the expand takes the lane
|
|
373
|
+
// that can read every term instead. The modifier families above cannot
|
|
374
|
+
// follow it — their nested `values` is a second hop only a document can
|
|
375
|
+
// make — which is why the lane is per-expand.
|
|
376
|
+
{
|
|
377
|
+
name: "tokens",
|
|
378
|
+
heading: "Tokens",
|
|
379
|
+
kind: "table",
|
|
380
|
+
relation: "ds:hasTokenBinding",
|
|
381
|
+
source: "sparql",
|
|
382
|
+
level: "detailed",
|
|
383
|
+
// Ordered by the READING order of the thing described: a node's
|
|
384
|
+
// styles, one key at a time, each key's fallback chain in the order
|
|
385
|
+
// the implementation walks it. The store's own scan order is
|
|
386
|
+
// undefined and put a node's two spacing keys either side of an
|
|
387
|
+
// unrelated one.
|
|
388
|
+
orderBy: ["node", "key", "rank"],
|
|
389
|
+
// The same sentence `Anatomy (DSL)` carries, because it is the same
|
|
390
|
+
// notation read from the other side: the anatomy's bracketed list is
|
|
391
|
+
// the chain, and `rank` is the position in it. A reader who has the
|
|
392
|
+
// rank column but not that sentence has no way to know that rank 2 is
|
|
393
|
+
// reached only when rank 1 does not resolve.
|
|
394
|
+
note: "A list value in the anatomy is the fallback chain the implementation reads, first wins; rank is the position in that chain.",
|
|
395
|
+
select: [
|
|
396
|
+
// The dotted name, not the symbol's IRI: it is the address
|
|
397
|
+
// `token lookup` and `token consumers --symbol` both take, so a row
|
|
398
|
+
// here is a query a reader can run.
|
|
399
|
+
{ name: "symbol", property: "ds:consumesSymbol/rdfs:label" },
|
|
400
|
+
{ name: "key", property: "anatomy:styleKey" },
|
|
401
|
+
{ name: "state", property: "anatomy:styleState" },
|
|
402
|
+
{ name: "rank", property: "ds:rank" },
|
|
403
|
+
// Blank on the block's OWN tree. `ds:viaBlock` is present on every
|
|
404
|
+
// record and its own definition says it equals the block in the
|
|
405
|
+
// own-tree case, so printing it raw put "Button" in all 24 of
|
|
406
|
+
// Button's rows — a cell that is only ever news when it differs.
|
|
407
|
+
{
|
|
408
|
+
name: "via",
|
|
409
|
+
property: "ds:viaBlock/ds:name",
|
|
410
|
+
blankWhenSelf: true,
|
|
411
|
+
},
|
|
412
|
+
{ name: "node", property: "ds:node" },
|
|
413
|
+
],
|
|
414
|
+
},
|
|
309
415
|
],
|
|
310
416
|
disclosure: {
|
|
311
417
|
levels: ["summary", "standard", "detailed"],
|
|
@@ -317,55 +423,822 @@ const designSystemStories = [
|
|
|
317
423
|
},
|
|
318
424
|
},
|
|
319
425
|
},
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
426
|
+
// The design-token SYMBOLS — S1 of the four token strata, keyed on the name
|
|
427
|
+
// literal the binding programme publishes.
|
|
428
|
+
//
|
|
429
|
+
// REPOINTED from `ds:Token`, a class no graph asserts. The shipped pack
|
|
430
|
+
// carries 0 instances of it and 745 `dt:TokenSymbol`, so every `token list`
|
|
431
|
+
// on every install answered an empty table while the population sat one
|
|
432
|
+
// namespace over — the same silent shape as reading a retired `ds:whenToUse`,
|
|
433
|
+
// and caught the same way (`listBudget.shipped.exec.test.ts` measured this
|
|
434
|
+
// story at 0 rows / 2 bytes). `ds:valueLight`/`ds:valueDark` go with it: a
|
|
435
|
+
// symbol's value is not a pair of theme columns but one row per POSITION in
|
|
436
|
+
// the coordinate space, which is what `token values` answers.
|
|
437
|
+
//
|
|
438
|
+
// NO `nameFallback`, deliberately. The kernel's IRI derivation publishes a
|
|
439
|
+
// dotted local name with SLASHES (`dt:color.text` → `color/text`), which
|
|
440
|
+
// contradicts the dotted notation ruled for symbol names and would make this
|
|
441
|
+
// answer disagree with the anatomy's spelling of the same symbol. The
|
|
442
|
+
// consequence is visible rather than hidden: until the pack ships
|
|
443
|
+
// `rdfs:label` on the symbols, `token list` publishes no rows and
|
|
444
|
+
// `token lookup` resolves no name. An empty answer that says so beats a
|
|
445
|
+
// populated one whose names nothing else recognises — and it is why `token`
|
|
446
|
+
// is still in `EMPTY_CORPUS_TODAY`.
|
|
326
447
|
{
|
|
327
448
|
noun: "token",
|
|
328
|
-
description: "List
|
|
329
|
-
toolDescription:
|
|
449
|
+
description: "List the design-token symbols.",
|
|
450
|
+
toolDescription: 'List the design-token SYMBOLS — logical dotted names (`color.text`), with the type and description from the symbol\'s OWN definition, and the symbol a channel provisions. The CSS custom-property names a stylesheet declares are variable_list. Example: token_list { type: "color" }.',
|
|
330
451
|
list: {
|
|
452
|
+
// Type and description are DEFINITION-level facts, and 393 of the 745
|
|
453
|
+
// symbols have more than one definition (`color.text` has 20). The one
|
|
454
|
+
// that speaks FOR the symbol is its own, and the graph already carries a
|
|
455
|
+
// path to it: every symbol the resolver reached has a BASE
|
|
456
|
+
// `dt:ResolvedValue` — the one with no `dt:coordinate` — and the HEAD of
|
|
457
|
+
// that value's `dt:resolutionChain` is the definition the value was
|
|
458
|
+
// authored in at the all-defaults position. Its `dt:tokenType` and its
|
|
459
|
+
// `w3c-tokens:description` are this row's two cells.
|
|
460
|
+
//
|
|
461
|
+
// The base restriction is SPELLED OUT rather than left to `DISTINCT`.
|
|
462
|
+
// 354 of the 519 values at a coordinate carry a chain too, and their
|
|
463
|
+
// heads are the definitions authored for those positions — a different
|
|
464
|
+
// definition, correctly so, and not this column's. Over the shipped
|
|
465
|
+
// corpus those heads happen to agree with the base head on both fields,
|
|
466
|
+
// so the unrestricted walk answers the same 745 rows; `FILTER NOT EXISTS`
|
|
467
|
+
// says WHICH value is meant instead of resting on that coincidence.
|
|
468
|
+
//
|
|
469
|
+
// Measured over the 745 symbols: 718 publish both fields, 27 blank both.
|
|
470
|
+
// The 27 are the 25 minted channels, which have no definition anywhere,
|
|
471
|
+
// plus `typography.heading.display` and its `.bold` twin, which have
|
|
472
|
+
// definitions but no resolved value to authorise one of them. Nothing
|
|
473
|
+
// publishes one field and blanks the other — a chain head carries both,
|
|
474
|
+
// or the symbol has no chain head.
|
|
475
|
+
//
|
|
476
|
+
// This REPLACED an agreement rule (publish what every definition agrees
|
|
477
|
+
// on, blank it when they disagree), and the two never disagree where the
|
|
478
|
+
// old one spoke: 0 of the 745 symbols have two definitions naming
|
|
479
|
+
// different types, and the 40 whose descriptions "disagreed" disagree
|
|
480
|
+
// only with a `semantic/modifier/**` definition — one position's wording,
|
|
481
|
+
// which the old rule let outvote the symbol's own. Those 40 now read
|
|
482
|
+
// their own description instead of a blank. What went with the old rule
|
|
483
|
+
// is its cost: a `COUNT(DISTINCT ...)` sub-select over 1,311 definitions
|
|
484
|
+
// made this the slowest body in the distribution. The paged walk that
|
|
485
|
+
// `listQuery.shipped.exec.test.ts` runs over it took 190 s, past its own
|
|
486
|
+
// 60-second timeout; over this query it takes 1.8 s, and the whole
|
|
487
|
+
// population comes back in 71 ms rather than 1.1 s a page.
|
|
331
488
|
query: [
|
|
332
|
-
"SELECT ?uri ?name ?
|
|
333
|
-
"
|
|
334
|
-
"
|
|
489
|
+
"SELECT DISTINCT ?uri ?name ?type ?description ?channelOf",
|
|
490
|
+
"WHERE {",
|
|
491
|
+
" ?uri a dt:TokenSymbol ;",
|
|
492
|
+
" rdfs:label ?name .",
|
|
493
|
+
// A channel IS a symbol after the binding programme, so the relation to
|
|
494
|
+
// the symbol it provisions is a column on this population rather than a
|
|
495
|
+
// noun of its own. Bound to the base symbol's LABEL, not its IRI: the
|
|
496
|
+
// filter column and the displayed column are one column, and an
|
|
497
|
+
// unbound IRI cell renders as a full IRI.
|
|
498
|
+
" OPTIONAL { ?uri dt:channelOf/rdfs:label ?channelOf }",
|
|
335
499
|
" OPTIONAL {",
|
|
336
|
-
" ?
|
|
337
|
-
"
|
|
500
|
+
" ?resolved dt:forSymbol ?uri ;",
|
|
501
|
+
" dt:resolutionChain/rdf:first ?definition .",
|
|
502
|
+
" FILTER NOT EXISTS { ?resolved dt:coordinate ?coordinate }",
|
|
503
|
+
" OPTIONAL { ?definition dt:tokenType/rdfs:label ?type }",
|
|
504
|
+
" OPTIONAL { ?definition w3c-tokens:description ?description }",
|
|
338
505
|
" }",
|
|
339
506
|
"}",
|
|
340
507
|
"ORDER BY ?name",
|
|
341
508
|
].join("\n"),
|
|
342
509
|
columns: [
|
|
510
|
+
{ field: "name", label: "Name" },
|
|
511
|
+
{ field: "type", label: "Type" },
|
|
512
|
+
{ field: "channelOf", label: "Channel of" },
|
|
513
|
+
{ field: "description", label: "Description" },
|
|
343
514
|
{ field: "uri", label: "IRI" },
|
|
515
|
+
],
|
|
516
|
+
filters: [
|
|
517
|
+
{
|
|
518
|
+
param: "type",
|
|
519
|
+
variable: "type",
|
|
520
|
+
// The seven typed members of the definition's type class, which is
|
|
521
|
+
// the same term the `type` column reads off the symbol's own
|
|
522
|
+
// definition. A type the ontology declares that no symbol is filed
|
|
523
|
+
// under is a calm empty list, not a bad argument.
|
|
524
|
+
vocabulary: {
|
|
525
|
+
query: [
|
|
526
|
+
"SELECT DISTINCT ?type WHERE {",
|
|
527
|
+
" ?kind a w3c-tokens:TokenType ;",
|
|
528
|
+
" rdfs:label ?type .",
|
|
529
|
+
"}",
|
|
530
|
+
].join("\n"),
|
|
531
|
+
},
|
|
532
|
+
description: "Filter by type.",
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
param: "channelOf",
|
|
536
|
+
variable: "channelOf",
|
|
537
|
+
// The dimension is "which SYMBOL", so the roster is EVERY symbol —
|
|
538
|
+
// not the far smaller set that happens to have a channel today.
|
|
539
|
+
// Asking for a symbol nothing provisions is the documented calm empty
|
|
540
|
+
// list, which is the whole reason a vocabulary is read from the graph
|
|
541
|
+
// rather than from the rows a page returned.
|
|
542
|
+
//
|
|
543
|
+
// Keyed on `rdfs:label`, the same term the column binds and the same
|
|
544
|
+
// term the lookup resolves by. All three move together or not at all.
|
|
545
|
+
vocabulary: {
|
|
546
|
+
query: [
|
|
547
|
+
"SELECT DISTINCT ?channelOf WHERE {",
|
|
548
|
+
" ?symbol a dt:TokenSymbol ;",
|
|
549
|
+
" rdfs:label ?channelOf .",
|
|
550
|
+
"}",
|
|
551
|
+
].join("\n"),
|
|
552
|
+
},
|
|
553
|
+
description: "Filter to one symbol's channels.",
|
|
554
|
+
},
|
|
555
|
+
],
|
|
556
|
+
search: {
|
|
557
|
+
variables: ["name", "description"],
|
|
558
|
+
description: "Search name and description.",
|
|
559
|
+
},
|
|
560
|
+
// No `emptyRecovery`: this list is empty only on an install whose store
|
|
561
|
+
// holds no token pack at all, and the kernel's generic hint already names
|
|
562
|
+
// both fixes for that (broaden the filter, or build the store). Anything a
|
|
563
|
+
// story added here would be a sentence about an empty store printed to
|
|
564
|
+
// readers who have 745 symbols and only missed with a filter.
|
|
565
|
+
},
|
|
566
|
+
verbs: [
|
|
567
|
+
{
|
|
568
|
+
verb: "values",
|
|
569
|
+
description: "List the value each symbol resolves to at each position, with its chain or its derivation.",
|
|
570
|
+
toolDescription: 'List the resolved token VALUES — one row per (symbol, position) the graph materialises, with the value and either its resolution chain or the symbol it derives from. Only MATERIALISED positions appear, not the permutation space: a position with no row falls through to the base symbol. A derived row carries a derivation and no value cell. Example: token_values { symbol: "color.text" }.',
|
|
571
|
+
// The resolved-value shape admits exactly one of a chain or a
|
|
572
|
+
// derivation, so BOTH are selected wherever a value is projected. A
|
|
573
|
+
// surface that selected only the chain would show a blank row for every
|
|
574
|
+
// one of the 165 channel routings — and channel values are precisely
|
|
575
|
+
// what the anatomy validator and the editor's completion ask about.
|
|
576
|
+
//
|
|
577
|
+
// Both are rdf:LISTs, not literals: `dt:resolutionChain` is a list of
|
|
578
|
+
// definition IRIs, so it needs `/rdf:rest*/rdf:first` and an aggregate
|
|
579
|
+
// to become one cell. The chain items are trimmed to the path inside
|
|
580
|
+
// the token files, which is the form the resolution chain is quoted in.
|
|
581
|
+
//
|
|
582
|
+
// The cell is a SET, and its order is NOT the list's. `GROUP_CONCAT`
|
|
583
|
+
// has no defined order in SPARQL and takes no `ORDER BY`, so the links
|
|
584
|
+
// of a multi-link chain may come back either way round — which a test
|
|
585
|
+
// pinning one spelling of a two-link chain found by flaking. Reading
|
|
586
|
+
// the cell as "which definitions this value passed through" is
|
|
587
|
+
// therefore right and reading it as "in what order" is not. The
|
|
588
|
+
// ORDERED anchor a caller usually wants is the chain's HEAD, the
|
|
589
|
+
// definition the value was authored in, and that is what the lookup's
|
|
590
|
+
// `values` expand projects with `rdf:first`.
|
|
591
|
+
query: [
|
|
592
|
+
"SELECT ?symbol ?position ?value ?derivedFrom",
|
|
593
|
+
' (GROUP_CONCAT(DISTINCT ?chainItem; SEPARATOR=" ") AS ?chain)',
|
|
594
|
+
"WHERE {",
|
|
595
|
+
" ?resolved a dt:ResolvedValue ;",
|
|
596
|
+
" dt:forSymbol ?symbolUri .",
|
|
597
|
+
" ?symbolUri rdfs:label ?symbol .",
|
|
598
|
+
" OPTIONAL { ?resolved dt:coordinate ?coordinate }",
|
|
599
|
+
" OPTIONAL { ?resolved dt:resolvesTo ?value }",
|
|
600
|
+
" OPTIONAL { ?resolved dt:derivedFrom/rdfs:label ?derivedFrom }",
|
|
601
|
+
" OPTIONAL {",
|
|
602
|
+
" ?resolved dt:resolutionChain/rdf:rest*/rdf:first ?chainUri .",
|
|
603
|
+
' BIND(REPLACE(STR(?chainUri), "^.*/file/", "") AS ?chainItem)',
|
|
604
|
+
" }",
|
|
605
|
+
// The coordinate's own dotted name, with the class prefix its IRI
|
|
606
|
+
// carries dropped: `dt:coordinate.mode.dark` displays and filters as
|
|
607
|
+
// `mode.dark`, which is how a position is written everywhere else.
|
|
608
|
+
// A value at the DEFAULT position carries no coordinate at all, and
|
|
609
|
+
// its cell is empty rather than a full IRI.
|
|
610
|
+
' BIND(REPLACE(REPLACE(STR(?coordinate), "^.*[/#]", ""), "^coordinate[.]", "") AS ?position)',
|
|
611
|
+
"}",
|
|
612
|
+
"GROUP BY ?resolved ?symbol ?position ?value ?derivedFrom",
|
|
613
|
+
"ORDER BY ?symbol ?position",
|
|
614
|
+
].join("\n"),
|
|
615
|
+
columns: [
|
|
616
|
+
{ field: "symbol", label: "Symbol" },
|
|
617
|
+
{ field: "position", label: "Position" },
|
|
618
|
+
{ field: "value", label: "Value" },
|
|
619
|
+
{ field: "chain", label: "Chain" },
|
|
620
|
+
{ field: "derivedFrom", label: "Derived from" },
|
|
621
|
+
],
|
|
622
|
+
filters: [
|
|
623
|
+
{
|
|
624
|
+
param: "symbol",
|
|
625
|
+
variable: "symbol",
|
|
626
|
+
vocabulary: {
|
|
627
|
+
query: [
|
|
628
|
+
"SELECT DISTINCT ?symbol WHERE {",
|
|
629
|
+
" ?s a dt:TokenSymbol ;",
|
|
630
|
+
" rdfs:label ?symbol .",
|
|
631
|
+
"}",
|
|
632
|
+
].join("\n"),
|
|
633
|
+
},
|
|
634
|
+
description: "Filter to one symbol.",
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
param: "position",
|
|
638
|
+
variable: "position",
|
|
639
|
+
// `set`, because ONE row can sit at several positions at once: a
|
|
640
|
+
// value asserted `dt:alsoAt` a second coordinate is one row
|
|
641
|
+
// belonging to both, and a filter comparing only the whole cell
|
|
642
|
+
// would answer such a row for neither.
|
|
643
|
+
match: "set",
|
|
644
|
+
vocabulary: {
|
|
645
|
+
query: [
|
|
646
|
+
"SELECT DISTINCT ?position WHERE {",
|
|
647
|
+
" ?c a dt:Coordinate .",
|
|
648
|
+
' BIND(REPLACE(REPLACE(STR(?c), "^.*[/#]", ""), "^coordinate[.]", "") AS ?position)',
|
|
649
|
+
"}",
|
|
650
|
+
].join("\n"),
|
|
651
|
+
},
|
|
652
|
+
description: "Filter to one position.",
|
|
653
|
+
},
|
|
654
|
+
],
|
|
655
|
+
search: {
|
|
656
|
+
variables: ["symbol", "value", "derivedFrom"],
|
|
657
|
+
description: "Search symbol, value, derivation.",
|
|
658
|
+
},
|
|
659
|
+
emptyRecovery: {
|
|
660
|
+
message: "Resolved token values come from the @canonical/token-ontology pack, and a value is only addressable by symbol once that pack publishes its name literals — a store built without that pack carries none.",
|
|
661
|
+
cli: "sources update",
|
|
662
|
+
},
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
verb: "consumers",
|
|
666
|
+
description: "List which blocks consume which token symbol, at which style key, state and rank.",
|
|
667
|
+
toolDescription: 'List the token BINDINGS the design system records — which block consumes which symbol, at which style key, state, rank and node. Every column is identity: two bindings differing only in state are different facts. The block is the CONSUMING block; via names the block whose anatomy the binding was authored in, and is blank when that is the consuming block itself. Name the symbol by its dotted name (symbol) or by a CSS variable standing for it (variable). Answers empty until the packs record bindings. Example: token_consumers { variable: "color-text" }.',
|
|
668
|
+
// Seven identity columns, and not one of them is decoration: a binding
|
|
669
|
+
// is identified by the whole tuple, so dropping `rank` or `node` would
|
|
670
|
+
// publish rows a caller cannot tell apart — which is worse than a wide
|
|
671
|
+
// table, because a deduplicating consumer would silently lose facts.
|
|
672
|
+
//
|
|
673
|
+
// `ds:hasTokenBinding` and its four siblings are DEFINED BY the
|
|
674
|
+
// design-system ontology only from the binding programme's records
|
|
675
|
+
// onward; today the shipped ontology defines none of them, and the `ds:`
|
|
676
|
+
// prefix IS bound, so this answers a calm empty list with the recovery
|
|
677
|
+
// below rather than failing. It starts answering with no code change.
|
|
678
|
+
//
|
|
679
|
+
// `?block` is the CONSUMING block and `?via` the block whose anatomy
|
|
680
|
+
// the binding was authored in, and the two are separate columns because
|
|
681
|
+
// they are separate facts. They were one: `?block` used to COALESCE the
|
|
682
|
+
// via name over the consuming block's, so a record Accordion carries
|
|
683
|
+
// because its anatomy embeds `Accordion.Item` printed as
|
|
684
|
+
// `Accordion.Item` — byte-identical to Accordion.Item's OWN record.
|
|
685
|
+
// `--symbol color.text` answered six rows reading `Button`, one per
|
|
686
|
+
// block that embeds a Button, and no reader could tell which component
|
|
687
|
+
// would change if the symbol did. Which component consumes the symbol
|
|
688
|
+
// is the fact this verb exists for, so it is the column the row leads
|
|
689
|
+
// with; the via is BLANK on a record sitting on the block's own tree —
|
|
690
|
+
// where the data asserts `ds:viaBlock` equal to the block itself —
|
|
691
|
+
// because "Button via Button" is not news and 24 of Button's rows
|
|
692
|
+
// would say it.
|
|
693
|
+
query: [
|
|
694
|
+
"SELECT ?block ?via ?symbol ?key ?state ?rank ?node ?uri",
|
|
695
|
+
' (GROUP_CONCAT(DISTINCT ?variableName; SEPARATOR=" ") AS ?variable)',
|
|
696
|
+
"WHERE {",
|
|
697
|
+
" ?blockUri ds:hasTokenBinding ?uri .",
|
|
698
|
+
" ?uri ds:consumesSymbol ?symbolUri .",
|
|
699
|
+
" ?symbolUri rdfs:label ?symbol .",
|
|
700
|
+
" OPTIONAL { ?uri anatomy:styleKey ?key }",
|
|
701
|
+
" OPTIONAL { ?uri anatomy:styleState ?state }",
|
|
702
|
+
" OPTIONAL { ?uri ds:rank ?rank }",
|
|
703
|
+
" OPTIONAL { ?uri ds:node ?node }",
|
|
704
|
+
" OPTIONAL { ?uri ds:viaBlock ?viaUri . OPTIONAL { ?viaUri ds:name ?viaName } }",
|
|
705
|
+
" OPTIONAL { ?blockUri ds:name ?blockName }",
|
|
706
|
+
// Every platform spelling of the consumed symbol, as a SET rather
|
|
707
|
+
// than a join that multiplies the row: 204 symbols carry both a
|
|
708
|
+
// kebab and a camelCase variable, and binding one row per variable
|
|
709
|
+
// would publish each binding twice under names a caller cannot tell
|
|
710
|
+
// apart. Aggregated, both spellings land in one cell and `--variable`
|
|
711
|
+
// set-matches either — which is also why the two spellings of one
|
|
712
|
+
// symbol return the SAME set rather than partitioning it.
|
|
713
|
+
" OPTIONAL {",
|
|
714
|
+
" ?variableUri dt:ofSymbol ?symbolUri ;",
|
|
715
|
+
" rdfs:label ?variableName .",
|
|
716
|
+
" }",
|
|
717
|
+
' BIND(COALESCE(?blockName, REPLACE(STR(?blockUri), "^.*[/#]", "")) AS ?block)',
|
|
718
|
+
// `IF` and not `COALESCE`: the blank says something a MISSING value
|
|
719
|
+
// cannot, because the via is present on every record and equals the
|
|
720
|
+
// block on its own tree. SPARQL evaluates only the taken arm of an
|
|
721
|
+
// `IF`, so the local-name fallback is never asked to name an unbound
|
|
722
|
+
// via.
|
|
723
|
+
" BIND(IF(BOUND(?viaUri) && ?viaUri != ?blockUri,",
|
|
724
|
+
' COALESCE(?viaName, REPLACE(STR(?viaUri), "^.*[/#]", "")),',
|
|
725
|
+
' "") AS ?via)',
|
|
726
|
+
"}",
|
|
727
|
+
"GROUP BY ?block ?via ?symbol ?key ?state ?rank ?node ?uri",
|
|
728
|
+
// `?via` second, so a block's OWN bindings (blank via, which sorts
|
|
729
|
+
// first) come before the ones it inherits, and the inherited ones
|
|
730
|
+
// stay grouped by the block they come from.
|
|
731
|
+
"ORDER BY ?block ?via ?symbol ?key ?state ?rank ?node",
|
|
732
|
+
].join("\n"),
|
|
733
|
+
// No `uri` COLUMN, though the record's IRI is still SELECTed: it is the
|
|
734
|
+
// row's subject and what keeps two bindings differing only in state
|
|
735
|
+
// apart, so `--format json` carries it exactly as before. What it is
|
|
736
|
+
// not is a cell worth a reader's eye. A binding record is a BLANK NODE,
|
|
737
|
+
// so it is not addressable — `graph inspect _:dda768d3…` answers
|
|
738
|
+
// INVALID_INPUT — and a blank node's label is re-minted on every store
|
|
739
|
+
// load, so the same row printed a different id on every run. And the
|
|
740
|
+
// `llm` renderer hoists a `uri` column to the HEAD of the line, ahead
|
|
741
|
+
// of every other cell, which is the slot the consuming block belongs
|
|
742
|
+
// in; a story cannot reorder that, so the column goes rather than the
|
|
743
|
+
// block staying second to an unusable id.
|
|
744
|
+
columns: [
|
|
745
|
+
{ field: "block", label: "Block" },
|
|
746
|
+
{ field: "via", label: "Via" },
|
|
747
|
+
{ field: "symbol", label: "Symbol" },
|
|
748
|
+
{ field: "variable", label: "Variables" },
|
|
749
|
+
{ field: "key", label: "Style key" },
|
|
750
|
+
{ field: "state", label: "State" },
|
|
751
|
+
{ field: "rank", label: "Rank" },
|
|
752
|
+
{ field: "node", label: "Node" },
|
|
753
|
+
],
|
|
754
|
+
filters: [
|
|
755
|
+
{
|
|
756
|
+
param: "symbol",
|
|
757
|
+
variable: "symbol",
|
|
758
|
+
vocabulary: {
|
|
759
|
+
query: [
|
|
760
|
+
"SELECT DISTINCT ?symbol WHERE {",
|
|
761
|
+
" ?s a dt:TokenSymbol ;",
|
|
762
|
+
" rdfs:label ?symbol .",
|
|
763
|
+
"}",
|
|
764
|
+
].join("\n"),
|
|
765
|
+
},
|
|
766
|
+
description: "Filter to one symbol.",
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
param: "variable",
|
|
770
|
+
variable: "variable",
|
|
771
|
+
// The SAME constraint as `--symbol`, named by the other spelling.
|
|
772
|
+
// A web implementer holds a CSS custom-property name, not a dotted
|
|
773
|
+
// symbol, so answering "what breaks if I change --color-text" used
|
|
774
|
+
// to take two calls and a spelling the caller did not start with.
|
|
775
|
+
// The join is in the query instead.
|
|
776
|
+
//
|
|
777
|
+
// `set`, because the cell is every platform spelling of the
|
|
778
|
+
// consumed symbol and one row legitimately belongs to all of them.
|
|
779
|
+
match: "set",
|
|
780
|
+
// The variable labels, the same source `variable lookup` resolves
|
|
781
|
+
// against — so a name that works there works here.
|
|
782
|
+
vocabulary: {
|
|
783
|
+
query: [
|
|
784
|
+
"SELECT DISTINCT ?variable WHERE {",
|
|
785
|
+
" ?v a dt:Variable ;",
|
|
786
|
+
" rdfs:label ?variable .",
|
|
787
|
+
"}",
|
|
788
|
+
].join("\n"),
|
|
789
|
+
},
|
|
790
|
+
// Two things a caller will otherwise assume, both wrong.
|
|
791
|
+
//
|
|
792
|
+
// A CHANNEL variable and its semantic sibling are DIFFERENT
|
|
793
|
+
// constraints: `--variable modifier-color-text` finds the blocks
|
|
794
|
+
// that bind the channel, `--variable color-text` those that bind
|
|
795
|
+
// the symbol, and neither includes the other. Whether a block's
|
|
796
|
+
// resolution eventually reaches the other through a fallback is a
|
|
797
|
+
// question about the consumed list, not about this single-symbol
|
|
798
|
+
// join, and blurring them here would answer a question nobody
|
|
799
|
+
// asked with rows nobody can check.
|
|
800
|
+
//
|
|
801
|
+
// And a variable standing for NO symbol has no answer down this
|
|
802
|
+
// path at all — 236 of them do — which is an empty answer for a
|
|
803
|
+
// reason the recovery below names, not evidence that nothing
|
|
804
|
+
// consumes it.
|
|
805
|
+
description: "A CSS variable name for the consumed symbol — the other spelling of the symbol parameter. A channel variable and its semantic sibling differ.",
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
param: "key",
|
|
809
|
+
variable: "key",
|
|
810
|
+
// The style-key REGISTRY, which the anatomy pack publishes as 111
|
|
811
|
+
// `anatomy:StyleKey` individuals. Their identity is the IRI and
|
|
812
|
+
// they carry no key literal, so the admissible spelling is the
|
|
813
|
+
// IRI's local name with the class prefix its minting adds dropped:
|
|
814
|
+
// `anatomy:key.appearance.background` is the key
|
|
815
|
+
// `appearance.background`, which is how the vocabulary's own
|
|
816
|
+
// examples write it.
|
|
817
|
+
//
|
|
818
|
+
// Read from the REGISTRY rather than from the records, and that is
|
|
819
|
+
// the point: no block has a binding record yet, so a roster read
|
|
820
|
+
// from records would be empty and would refuse every key a caller
|
|
821
|
+
// could legitimately ask about. The registry is the graph's
|
|
822
|
+
// statement of what a key may be; the records are the population.
|
|
823
|
+
vocabulary: {
|
|
824
|
+
query: [
|
|
825
|
+
"SELECT DISTINCT ?key WHERE {",
|
|
826
|
+
" ?styleKey a anatomy:StyleKey .",
|
|
827
|
+
' BIND(REPLACE(REPLACE(STR(?styleKey), "^.*[/#]", ""), "^key[.]", "") AS ?key)',
|
|
828
|
+
"}",
|
|
829
|
+
].join("\n"),
|
|
830
|
+
},
|
|
831
|
+
description: "Filter to one style key.",
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
param: "state",
|
|
835
|
+
variable: "state",
|
|
836
|
+
// The closed interaction-state vocabulary, read from the shape that
|
|
837
|
+
// closes it rather than transcribed here: the anatomy pack's shapes
|
|
838
|
+
// constrain `anatomy:styleState` with an `sh:in` list, so the five
|
|
839
|
+
// admissible states are a query over that list. Hard-coding them
|
|
840
|
+
// would be the "don't hard-code the slugs" defect with an extra
|
|
841
|
+
// step — the graph already says it.
|
|
842
|
+
vocabulary: {
|
|
843
|
+
query: [
|
|
844
|
+
"SELECT DISTINCT ?state WHERE {",
|
|
845
|
+
" ?shape sh:path anatomy:styleState ;",
|
|
846
|
+
" sh:in/rdf:rest*/rdf:first ?state .",
|
|
847
|
+
"}",
|
|
848
|
+
].join("\n"),
|
|
849
|
+
},
|
|
850
|
+
description: "Filter to one interaction state.",
|
|
851
|
+
},
|
|
852
|
+
],
|
|
853
|
+
search: {
|
|
854
|
+
variables: ["block", "via", "symbol", "key", "state", "node"],
|
|
855
|
+
description: "Search block, via, symbol, key, state and node.",
|
|
856
|
+
},
|
|
857
|
+
// Deliberately `sources update`: unlike `standard list`, this story's
|
|
858
|
+
// data does NOT ride the embedded snapshot — the binding records are
|
|
859
|
+
// written by the design-system packs, so an empty answer here can be a
|
|
860
|
+
// store that predates them.
|
|
861
|
+
//
|
|
862
|
+
// CAN be, not is — which is why the message opens on the two cases
|
|
863
|
+
// rather than asserting one. This text prints under a filtered miss too
|
|
864
|
+
// (`--symbol color.text`), where "nothing is recorded at all" would be a
|
|
865
|
+
// claim the answer cannot support, so it names both readings and hands
|
|
866
|
+
// the reader the one command that separates them.
|
|
867
|
+
emptyRecovery: {
|
|
868
|
+
message: "Either no component uses this token, or no component is recorded as using any token yet — which components use which tokens comes from the component anatomies in the design-system document, and a copy of the graph built before any anatomy named its tokens is empty for every token. Run the same command without `--symbol` to tell the two apart: an empty unfiltered answer means the graph predates the anatomies and fills in once they are written and the graph is rebuilt. If you asked about a CSS variable rather than a token: some variables are computed from others (the `--hover--…` and `--disabled--…` ones, for example) and stand for no token, so nothing is ever recorded as using them; `pragma variable chain --variable <name>` shows what such a variable ends up as.",
|
|
869
|
+
cli: "sources update",
|
|
870
|
+
},
|
|
871
|
+
},
|
|
872
|
+
],
|
|
873
|
+
lookup: {
|
|
874
|
+
source: "sparql",
|
|
875
|
+
// `rdfs:label`, matching the `name` the list publishes — the two-step
|
|
876
|
+
// grammar is that a row's `name` goes VERBATIM to lookup. Both halves
|
|
877
|
+
// REQUIRE the literal, so both are empty together rather than one
|
|
878
|
+
// publishing names the other cannot resolve.
|
|
879
|
+
by: "rdfs:label",
|
|
880
|
+
type: "dt:TokenSymbol",
|
|
881
|
+
description: "Look up one or more token symbols by dotted name, IRI, or glob.",
|
|
882
|
+
toolDescription: 'Get one design-token symbol in full: its own type and description, every definition behind it with that definition\'s own type and description, the modifier families that may rebind it, and the value it resolves to at each position. Address it by the dotted name token_list publishes (`color.text`), by prefixed name, by IRI, or by a glob. Example: token_lookup { name: ["color.text"] }.',
|
|
883
|
+
fields: [
|
|
884
|
+
// Single-valued: a channel provisions exactly one symbol.
|
|
885
|
+
{
|
|
886
|
+
name: "channelOf",
|
|
887
|
+
property: "dt:channelOf/rdfs:label",
|
|
888
|
+
label: "Channel of",
|
|
889
|
+
},
|
|
890
|
+
// The same pair `token list` publishes, reached the same way: the head
|
|
891
|
+
// of a resolved value's chain is the definition that value was authored
|
|
892
|
+
// in, so these two read the symbol's OWN definition rather than
|
|
893
|
+
// sampling one of the twenty behind `color.text`.
|
|
894
|
+
//
|
|
895
|
+
// A lookup field is a property PATH, so it cannot spell the
|
|
896
|
+
// `FILTER NOT EXISTS` that restricts the list's walk to the BASE value,
|
|
897
|
+
// and here it does not have to. 354 symbols have more than one chain
|
|
898
|
+
// head — one per materialised position — and over the shipped corpus no
|
|
899
|
+
// symbol's heads name two types or two descriptions, so the path is
|
|
900
|
+
// multi-valued with one value repeated and `firstRowPerEntity` keeping
|
|
901
|
+
// the first is a choice between identical answers. Were a position's
|
|
902
|
+
// head ever to differ, the `definitions` expand is where the difference
|
|
903
|
+
// is readable, because it shows every definition APART.
|
|
904
|
+
{
|
|
905
|
+
name: "type",
|
|
906
|
+
property: "^dt:forSymbol/dt:resolutionChain/rdf:first/dt:tokenType/rdfs:label",
|
|
907
|
+
label: "Type",
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
name: "description",
|
|
911
|
+
property: "^dt:forSymbol/dt:resolutionChain/rdf:first/w3c-tokens:description",
|
|
912
|
+
label: "Description",
|
|
913
|
+
},
|
|
914
|
+
],
|
|
915
|
+
expand: [
|
|
916
|
+
{
|
|
917
|
+
name: "definitions",
|
|
918
|
+
heading: "Definitions",
|
|
919
|
+
kind: "table",
|
|
920
|
+
// The inverse edge: definitions point AT the symbol
|
|
921
|
+
// (`?definition dt:symbol ?uri`), so the relation from the symbol is
|
|
922
|
+
// `^dt:symbol`. 1,311 definitions stand behind 745 symbols.
|
|
923
|
+
relation: "^dt:symbol",
|
|
924
|
+
select: [
|
|
925
|
+
{ name: "file", property: "w3c-tokens:inFile/w3c-tokens:path" },
|
|
926
|
+
{ name: "type", property: "dt:tokenType/rdfs:label" },
|
|
927
|
+
{ name: "description", property: "w3c-tokens:description" },
|
|
928
|
+
],
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
name: "coverage",
|
|
932
|
+
heading: "Covered by",
|
|
933
|
+
// Coverage hangs on the FAMILY, not on the symbol
|
|
934
|
+
// (`?family dt:covers ?symbol`), so this is the inverse too. The
|
|
935
|
+
// family is a `ds:` entity, so its name comes from the
|
|
936
|
+
// design-system pack rather than the token ontology.
|
|
937
|
+
relation: "^dt:covers",
|
|
938
|
+
select: [{ name: "family", property: "ds:name" }],
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
name: "values",
|
|
942
|
+
heading: "Values",
|
|
943
|
+
kind: "table",
|
|
944
|
+
relation: "^dt:forSymbol",
|
|
945
|
+
// BOTH the chain and the derivation, for the reason `token values`
|
|
946
|
+
// states: the shape admits exactly one of them, and selecting only
|
|
947
|
+
// the chain would blank every channel routing.
|
|
948
|
+
//
|
|
949
|
+
// `rdf:first` and NOT `/rdf:rest*/rdf:first`, which is the walk
|
|
950
|
+
// `token values` uses. An expand's child field is a plain triple with
|
|
951
|
+
// no aggregate available, so a multi-hop chain multiplies the CHILD:
|
|
952
|
+
// 204 of the 1,072 values carry a chain of 2 or 3 links, and
|
|
953
|
+
// `color.background.container` rendered four "Values" rows for its
|
|
954
|
+
// two positions, each repeating the same value beside a different
|
|
955
|
+
// link. A caller counting positions would have read that as four.
|
|
956
|
+
// The head of the list is the definition the value was AUTHORED in
|
|
957
|
+
// (the tail is what it aliased through to a primitive), so one link
|
|
958
|
+
// per row is both correct and the most useful one; the full walk is
|
|
959
|
+
// `token values`, which can GROUP_CONCAT it into a single cell.
|
|
960
|
+
select: [
|
|
961
|
+
{ name: "position", property: "dt:coordinate" },
|
|
962
|
+
{ name: "value", property: "dt:resolvesTo" },
|
|
963
|
+
{ name: "chain", property: "dt:resolutionChain/rdf:first" },
|
|
964
|
+
{ name: "derivedFrom", property: "dt:derivedFrom/rdfs:label" },
|
|
965
|
+
],
|
|
966
|
+
},
|
|
967
|
+
],
|
|
968
|
+
sample: {
|
|
969
|
+
fixedCount: true,
|
|
970
|
+
toolDescription: "Return random complete design-token symbols — definitions, coverage and resolved values — as exemplars. Use BEFORE writing queries to see real data shapes. Example: token_sample {}.",
|
|
971
|
+
},
|
|
972
|
+
},
|
|
973
|
+
},
|
|
974
|
+
// The platform VARIABLES — S4, the stylesheet's own names for the values.
|
|
975
|
+
//
|
|
976
|
+
// A SECOND noun rather than a flag on `token`, and one measurement settles
|
|
977
|
+
// it: 236 of the 1,156 variables stand for NO symbol at all — legacy twins
|
|
978
|
+
// the ontology itself names, plus the computed states and resets.
|
|
979
|
+
// `--disabled--color-text` and `--modifier-color-text` are nobody's symbol, so
|
|
980
|
+
// a surface keyed on symbols cannot address them. The cut is by STRATUM ROLE,
|
|
981
|
+
// not by platform: the platform is read out of the IRI base as an ordinary
|
|
982
|
+
// filter, so a second platform's catalogue arrives as one more value of
|
|
983
|
+
// `--platform` and not as a noun of its own.
|
|
984
|
+
//
|
|
985
|
+
// The published name is the label with its leading `--` STRIPPED, and that is
|
|
986
|
+
// what makes the noun usable at all: `--color-text` cannot be typed as a
|
|
987
|
+
// positional argument — the parser answers `unknown option '--color-text'`
|
|
988
|
+
// and a glob is no escape. Upstream publishes the stripped form as
|
|
989
|
+
// `rdfs:label`, and the stripping is measurably safe: over the 1,156
|
|
990
|
+
// variables it produces 1,156 distinct names and collides with no symbol
|
|
991
|
+
// name. `variable.parity.test.ts` pins both halves.
|
|
992
|
+
{
|
|
993
|
+
noun: "variable",
|
|
994
|
+
description: "List the platform variables the design tokens are emitted as.",
|
|
995
|
+
toolDescription: 'List the platform VARIABLES a stylesheet declares as CSS custom properties, with the symbol each stands for, its tier, visibility and the coordinates it is selected at. 236 stand for no symbol, so token_list cannot reach them. Address one WITHOUT its leading dashes (`color-text`). Example: variable_list { symbol: "color.text" }.',
|
|
996
|
+
list: {
|
|
997
|
+
query: [
|
|
998
|
+
"SELECT ?uri ?name ?platform ?symbol ?tier ?visibility",
|
|
999
|
+
' (GROUP_CONCAT(DISTINCT ?coordinateName; SEPARATOR=" ") AS ?coordinate)',
|
|
1000
|
+
"WHERE {",
|
|
1001
|
+
" ?uri a dt:Variable ;",
|
|
1002
|
+
" rdfs:label ?name .",
|
|
1003
|
+
" OPTIONAL { ?uri dt:ofSymbol/rdfs:label ?symbol }",
|
|
1004
|
+
" OPTIONAL { ?uri dt:tier ?tierUri }",
|
|
1005
|
+
" OPTIONAL { ?uri dt:visibility ?visibilityUri }",
|
|
1006
|
+
// A variable is selected at a coordinate two ways, and both count: the
|
|
1007
|
+
// CONDITION its declaration sits under selects one
|
|
1008
|
+
// (`.success` → `criticality.success`), and a declaration may assert a
|
|
1009
|
+
// second directly (`dt:alsoAt`, which is `mode.dark` for all 261 of
|
|
1010
|
+
// them). 305 of the 1,156 variables reach at least one coordinate.
|
|
1011
|
+
" OPTIONAL {",
|
|
1012
|
+
" { ?uri dt:declaredAt/dt:under/dt:selectsCoordinate ?coordinateUri }",
|
|
1013
|
+
" UNION",
|
|
1014
|
+
" { ?uri dt:declaredAt/dt:alsoAt ?coordinateUri }",
|
|
1015
|
+
' BIND(REPLACE(REPLACE(STR(?coordinateUri), "^.*[/#]", ""), "^coordinate[.]", "") AS ?coordinateName)',
|
|
1016
|
+
" }",
|
|
1017
|
+
// The platform, read out of the IRI base rather than asserted: every
|
|
1018
|
+
// variable is minted under `…/s4/<platform>/`. STRAFTER/STRBEFORE
|
|
1019
|
+
// rather than a regex so a variable whose IRI carries no such segment
|
|
1020
|
+
// answers an EMPTY cell instead of its own full IRI, which is what a
|
|
1021
|
+
// failed REPLACE returns.
|
|
1022
|
+
' BIND(STRBEFORE(STRAFTER(STR(?uri), "/s4/"), "/") AS ?platform)',
|
|
1023
|
+
' BIND(REPLACE(REPLACE(STR(?tierUri), "^.*[/#]", ""), "^tier[.]", "") AS ?tier)',
|
|
1024
|
+
' BIND(REPLACE(REPLACE(STR(?visibilityUri), "^.*[/#]", ""), "^visibility[.]", "") AS ?visibility)',
|
|
1025
|
+
"}",
|
|
1026
|
+
"GROUP BY ?uri ?name ?platform ?symbol ?tier ?visibility",
|
|
1027
|
+
"ORDER BY ?name",
|
|
1028
|
+
].join("\n"),
|
|
1029
|
+
columns: [
|
|
344
1030
|
{ field: "name", label: "Name" },
|
|
345
|
-
{ field: "
|
|
1031
|
+
{ field: "symbol", label: "Symbol" },
|
|
1032
|
+
{ field: "tier", label: "Tier" },
|
|
1033
|
+
{ field: "visibility", label: "Visibility" },
|
|
1034
|
+
{ field: "platform", label: "Platform" },
|
|
1035
|
+
{ field: "coordinate", label: "Coordinates" },
|
|
1036
|
+
{ field: "uri", label: "IRI" },
|
|
1037
|
+
],
|
|
1038
|
+
filters: [
|
|
1039
|
+
{
|
|
1040
|
+
param: "platform",
|
|
1041
|
+
variable: "platform",
|
|
1042
|
+
// The vocabulary is a query over the IRI base, exactly as the column
|
|
1043
|
+
// is — the platform is not asserted anywhere, so the file identity
|
|
1044
|
+
// in the IRI is the only thing that states it. One value today
|
|
1045
|
+
// (`web`); a second platform's catalogue adds itself here with no
|
|
1046
|
+
// edit.
|
|
1047
|
+
vocabulary: {
|
|
1048
|
+
query: [
|
|
1049
|
+
"SELECT DISTINCT ?platform WHERE {",
|
|
1050
|
+
" ?v a dt:Variable .",
|
|
1051
|
+
' BIND(STRBEFORE(STRAFTER(STR(?v), "/s4/"), "/") AS ?platform)',
|
|
1052
|
+
"}",
|
|
1053
|
+
].join("\n"),
|
|
1054
|
+
},
|
|
1055
|
+
description: "Filter by platform.",
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
param: "symbol",
|
|
1059
|
+
variable: "symbol",
|
|
1060
|
+
// The symbol roster, read the same way `token list`'s `channelOf`
|
|
1061
|
+
// filter reads it: every symbol, keyed on `rdfs:label`.
|
|
1062
|
+
vocabulary: {
|
|
1063
|
+
query: [
|
|
1064
|
+
"SELECT DISTINCT ?symbol WHERE {",
|
|
1065
|
+
" ?s a dt:TokenSymbol ;",
|
|
1066
|
+
" rdfs:label ?symbol .",
|
|
1067
|
+
"}",
|
|
1068
|
+
].join("\n"),
|
|
1069
|
+
},
|
|
1070
|
+
description: "Filter to one symbol.",
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
param: "tier",
|
|
1074
|
+
variable: "tier",
|
|
1075
|
+
vocabulary: {
|
|
1076
|
+
query: [
|
|
1077
|
+
"SELECT DISTINCT ?tier WHERE {",
|
|
1078
|
+
" ?t a dt:Tier .",
|
|
1079
|
+
' BIND(REPLACE(REPLACE(STR(?t), "^.*[/#]", ""), "^tier[.]", "") AS ?tier)',
|
|
1080
|
+
"}",
|
|
1081
|
+
].join("\n"),
|
|
1082
|
+
},
|
|
1083
|
+
description: "Filter by tier.",
|
|
1084
|
+
},
|
|
1085
|
+
{
|
|
1086
|
+
param: "visibility",
|
|
1087
|
+
variable: "visibility",
|
|
1088
|
+
vocabulary: {
|
|
1089
|
+
query: [
|
|
1090
|
+
"SELECT DISTINCT ?visibility WHERE {",
|
|
1091
|
+
" ?v a dt:Visibility .",
|
|
1092
|
+
' BIND(REPLACE(REPLACE(STR(?v), "^.*[/#]", ""), "^visibility[.]", "") AS ?visibility)',
|
|
1093
|
+
"}",
|
|
1094
|
+
].join("\n"),
|
|
1095
|
+
},
|
|
1096
|
+
description: "Filter by visibility.",
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
param: "coordinate",
|
|
1100
|
+
variable: "coordinate",
|
|
1101
|
+
// `set`, and it has to be: `--modifier-color-text` is selected at 17
|
|
1102
|
+
// coordinates at once, so its cell is the whole set its declarations
|
|
1103
|
+
// reach and a filter comparing the whole cell would answer for none
|
|
1104
|
+
// of them. The cell is a `GROUP_CONCAT`, so this predicate can only
|
|
1105
|
+
// run after aggregation — which is why the page wraps the query.
|
|
1106
|
+
match: "set",
|
|
1107
|
+
vocabulary: {
|
|
1108
|
+
query: [
|
|
1109
|
+
"SELECT DISTINCT ?coordinate WHERE {",
|
|
1110
|
+
" ?c a dt:Coordinate .",
|
|
1111
|
+
' BIND(REPLACE(REPLACE(STR(?c), "^.*[/#]", ""), "^coordinate[.]", "") AS ?coordinate)',
|
|
1112
|
+
"}",
|
|
1113
|
+
].join("\n"),
|
|
1114
|
+
},
|
|
1115
|
+
description: "Filter to one coordinate.",
|
|
1116
|
+
},
|
|
346
1117
|
],
|
|
1118
|
+
search: {
|
|
1119
|
+
variables: ["name", "symbol"],
|
|
1120
|
+
description: "Search name and symbol.",
|
|
1121
|
+
},
|
|
347
1122
|
emptyRecovery: {
|
|
348
|
-
message: "
|
|
1123
|
+
message: "Platform variables come from the @canonical/token-ontology pack, and a variable is only addressable once that pack publishes its name literals — a store built without that pack carries none.",
|
|
349
1124
|
cli: "sources update",
|
|
350
1125
|
},
|
|
351
1126
|
},
|
|
1127
|
+
verbs: [
|
|
1128
|
+
{
|
|
1129
|
+
verb: "chain",
|
|
1130
|
+
description: "List the walk from a variable to every symbol it reaches, through every variable in between.",
|
|
1131
|
+
toolDescription: 'List the resolution WALK: every (variable, symbol) pair a variable reaches through what its declarations reference, transitively — what a variable finally means. The closure runs over every declaration of every hop, so one variable can reach dozens of pairs. Example: variable_chain { variable: "modifier-color-text" }.',
|
|
1132
|
+
// ONE property path carries the whole walk, which is why this is a
|
|
1133
|
+
// query and not a traversal in code. `dt:references` is an rdf:List of
|
|
1134
|
+
// the variables a declaration's value reads, so each hop is
|
|
1135
|
+
// `dt:declaredAt/dt:references/rdf:rest*/rdf:first`, and the `+` makes
|
|
1136
|
+
// the whole thing transitive. The terminal is a variable that stands
|
|
1137
|
+
// for a symbol, which is what `dt:ofSymbol` reads.
|
|
1138
|
+
query: [
|
|
1139
|
+
"SELECT ?variable ?reaches ?symbol",
|
|
1140
|
+
"WHERE {",
|
|
1141
|
+
" ?uri a dt:Variable ;",
|
|
1142
|
+
" rdfs:label ?variable .",
|
|
1143
|
+
" ?uri (dt:declaredAt/dt:references/rdf:rest*/rdf:first)+ ?reachedUri .",
|
|
1144
|
+
" ?reachedUri dt:ofSymbol ?symbolUri ;",
|
|
1145
|
+
" rdfs:label ?reaches .",
|
|
1146
|
+
" ?symbolUri rdfs:label ?symbol .",
|
|
1147
|
+
"}",
|
|
1148
|
+
"ORDER BY ?variable ?reaches ?symbol",
|
|
1149
|
+
].join("\n"),
|
|
1150
|
+
columns: [
|
|
1151
|
+
{ field: "variable", label: "Variable" },
|
|
1152
|
+
{ field: "reaches", label: "Reaches" },
|
|
1153
|
+
{ field: "symbol", label: "Symbol" },
|
|
1154
|
+
],
|
|
1155
|
+
filters: [
|
|
1156
|
+
{
|
|
1157
|
+
param: "variable",
|
|
1158
|
+
variable: "variable",
|
|
1159
|
+
// The variable roster, keyed on the same `rdfs:label` the column
|
|
1160
|
+
// binds and the lookup resolves by — the CSS name with its leading
|
|
1161
|
+
// `--` already stripped, which is the only form typable as a
|
|
1162
|
+
// positional. `variable.parity.test.ts` pins that the stripping is
|
|
1163
|
+
// injective and collides with no symbol name.
|
|
1164
|
+
vocabulary: {
|
|
1165
|
+
query: [
|
|
1166
|
+
"SELECT DISTINCT ?variable WHERE {",
|
|
1167
|
+
" ?v a dt:Variable ;",
|
|
1168
|
+
" rdfs:label ?variable .",
|
|
1169
|
+
"}",
|
|
1170
|
+
].join("\n"),
|
|
1171
|
+
},
|
|
1172
|
+
description: "Filter to one variable.",
|
|
1173
|
+
},
|
|
1174
|
+
{
|
|
1175
|
+
param: "symbol",
|
|
1176
|
+
variable: "symbol",
|
|
1177
|
+
vocabulary: {
|
|
1178
|
+
query: [
|
|
1179
|
+
"SELECT DISTINCT ?symbol WHERE {",
|
|
1180
|
+
" ?s a dt:TokenSymbol ;",
|
|
1181
|
+
" rdfs:label ?symbol .",
|
|
1182
|
+
"}",
|
|
1183
|
+
].join("\n"),
|
|
1184
|
+
},
|
|
1185
|
+
description: "Filter to one symbol.",
|
|
1186
|
+
},
|
|
1187
|
+
],
|
|
1188
|
+
emptyRecovery: {
|
|
1189
|
+
message: "A resolution walk follows the declarations the @canonical/token-ontology pack provides, and the walk is only addressable by name once that pack publishes its name literals — a store built without that pack carries none.",
|
|
1190
|
+
cli: "sources update",
|
|
1191
|
+
},
|
|
1192
|
+
},
|
|
1193
|
+
],
|
|
352
1194
|
lookup: {
|
|
353
1195
|
source: "sparql",
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
1196
|
+
// `rdfs:label`, matching the `name` the list publishes, and with NO
|
|
1197
|
+
// `nameFallback` for the same reason `token` has none: the kernel's IRI
|
|
1198
|
+
// derivation would publish `--color-text` with its dashes intact and its
|
|
1199
|
+
// dots as slashes, and a `--`-prefixed positional cannot be typed at all.
|
|
1200
|
+
by: "rdfs:label",
|
|
1201
|
+
type: "dt:Variable",
|
|
1202
|
+
description: "Look up one or more platform variables by name (without the leading dashes), IRI, or glob.",
|
|
1203
|
+
toolDescription: 'Get one platform variable in full: its symbol, tier, visibility, and EVERY place it is declared — the selector and at-rule stack, the emitted value, the source location, the coordinate it also applies at, and the derivation. Address it by the CSS name WITHOUT its leading dashes (`color-text`). Example: variable_lookup { name: ["color-text"] }.',
|
|
357
1204
|
fields: [
|
|
1205
|
+
{ name: "symbol", property: "dt:ofSymbol/rdfs:label", label: "Symbol" },
|
|
1206
|
+
{ name: "tier", property: "dt:tier", label: "Tier" },
|
|
1207
|
+
{ name: "visibility", property: "dt:visibility", label: "Visibility" },
|
|
1208
|
+
],
|
|
1209
|
+
expand: [
|
|
358
1210
|
{
|
|
359
|
-
name: "
|
|
360
|
-
|
|
361
|
-
|
|
1211
|
+
name: "declarations",
|
|
1212
|
+
heading: "Declarations",
|
|
1213
|
+
kind: "table",
|
|
1214
|
+
relation: "dt:declaredAt",
|
|
1215
|
+
// 927 variables are declared once; the rest up to 17 times, which is
|
|
1216
|
+
// why this is an expand and not a set of fields.
|
|
1217
|
+
select: [
|
|
1218
|
+
{ name: "under", property: "dt:under" },
|
|
1219
|
+
{ name: "selector", property: "dt:under/dt-web:selector" },
|
|
1220
|
+
// The at-rule STACK, not one at-rule: `dt-web:inAtRule` is an
|
|
1221
|
+
// rdf:List, so the walk is `/rdf:rest*/rdf:first`. One condition of
|
|
1222
|
+
// the 31 nests two levels deep and so contributes two rows for one
|
|
1223
|
+
// declaration — that is the stack, read outermost-in, rather than a
|
|
1224
|
+
// duplicate.
|
|
1225
|
+
{
|
|
1226
|
+
name: "inAtRule",
|
|
1227
|
+
property: "dt:under/dt-web:inAtRule/rdf:rest*/rdf:first",
|
|
1228
|
+
},
|
|
1229
|
+
{ name: "emits", property: "dt:emits" },
|
|
1230
|
+
// `dt:at` is the SOURCE LOCATION (`modifiers.theme.css:322`), not a
|
|
1231
|
+
// coordinate; `dt:alsoAt` is the coordinate. The two read alike and
|
|
1232
|
+
// mean different things, which is why both are labelled.
|
|
1233
|
+
{ name: "at", property: "dt:at", label: "source" },
|
|
1234
|
+
{ name: "alsoAt", property: "dt:alsoAt", label: "alsoAt" },
|
|
1235
|
+
{ name: "derives", property: "dt:derives" },
|
|
1236
|
+
],
|
|
362
1237
|
},
|
|
363
|
-
{ name: "valueLight", property: "ds:valueLight", label: "Light value" },
|
|
364
|
-
{ name: "valueDark", property: "ds:valueDark", label: "Dark value" },
|
|
365
1238
|
],
|
|
366
1239
|
sample: {
|
|
367
1240
|
fixedCount: true,
|
|
368
|
-
toolDescription: "Return
|
|
1241
|
+
toolDescription: "Return random complete platform variables — symbol, tier, visibility and every declaration — as exemplars. Use BEFORE writing queries to see real data shapes. Example: variable_sample {}.",
|
|
369
1242
|
},
|
|
370
1243
|
},
|
|
371
1244
|
},
|
|
@@ -378,6 +1251,16 @@ const designSystemStories = [
|
|
|
378
1251
|
noun: "modifier",
|
|
379
1252
|
description: "List all modifier families.",
|
|
380
1253
|
toolDescription: "List all modifier families with their values. Use when browsing which modifier families exist and the values each allows. Example: modifier_list {}.",
|
|
1254
|
+
// Tiered like blocks — 11 of the modifier families carry a `ds:tier` — so
|
|
1255
|
+
// the same scope, declared with the same four terms. The scope is per NOUN
|
|
1256
|
+
// because being tiered is a fact about the entities, and the design
|
|
1257
|
+
// system's token symbols and code standards carry nothing of the kind.
|
|
1258
|
+
tierScope: {
|
|
1259
|
+
type: "ds:Tier",
|
|
1260
|
+
via: "ds:tier",
|
|
1261
|
+
by: "ds:name",
|
|
1262
|
+
base: "ds:global",
|
|
1263
|
+
},
|
|
381
1264
|
list: {
|
|
382
1265
|
query: [
|
|
383
1266
|
"SELECT ?uri ?name",
|
|
@@ -433,7 +1316,7 @@ const designSystemStories = [
|
|
|
433
1316
|
{
|
|
434
1317
|
noun: "tier",
|
|
435
1318
|
description: "List all tiers in the design system ontology.",
|
|
436
|
-
toolDescription: "List all tiers in the design-system ontology. Use when
|
|
1319
|
+
toolDescription: "List all tiers in the design-system ontology. Use when picking the tier to read with: the `tier` parameter scopes a read to one tier plus its ancestors, and this list is never scoped itself. Example: tier_list {}.",
|
|
437
1320
|
list: {
|
|
438
1321
|
query: [
|
|
439
1322
|
"SELECT ?uri ?name WHERE {",
|
|
@@ -474,6 +1357,16 @@ const conceptStory = {
|
|
|
474
1357
|
noun: "concept",
|
|
475
1358
|
description: "List design-system concepts.",
|
|
476
1359
|
toolDescription: 'List design-system concepts — long-form foundations, how-to guides, and decision guides not bound to a single UI block. Optionally filter by type or search. Example: concept_list { type: "Explanation" }.',
|
|
1360
|
+
// Concepts carry a `ds:tier` too (4 of them do), so they are scoped on the
|
|
1361
|
+
// same terms as blocks and modifier families. Its `list` publishes no tier
|
|
1362
|
+
// COLUMN and does not need to: the scope constrains the entity through
|
|
1363
|
+
// `ds:tier`, not a projected cell.
|
|
1364
|
+
tierScope: {
|
|
1365
|
+
type: "ds:Tier",
|
|
1366
|
+
via: "ds:tier",
|
|
1367
|
+
by: "ds:name",
|
|
1368
|
+
base: "ds:global",
|
|
1369
|
+
},
|
|
477
1370
|
list: {
|
|
478
1371
|
query: [
|
|
479
1372
|
"SELECT ?uri ?name ?type ?summary",
|
|
@@ -517,7 +1410,7 @@ const conceptStory = {
|
|
|
517
1410
|
description: "Search in name and summary.",
|
|
518
1411
|
},
|
|
519
1412
|
emptyRecovery: {
|
|
520
|
-
message: "
|
|
1413
|
+
message: "Concepts come from the @canonical/design-system pack, and a local store built without it carries none — refresh it.",
|
|
521
1414
|
cli: "sources update",
|
|
522
1415
|
},
|
|
523
1416
|
},
|
|
@@ -641,7 +1534,7 @@ const implementationStory = {
|
|
|
641
1534
|
description: "Search in block and library name.",
|
|
642
1535
|
},
|
|
643
1536
|
emptyRecovery: {
|
|
644
|
-
message: "
|
|
1537
|
+
message: "Implementations come from the @canonical/ds-implementations pack, and a local store built without it carries none — refresh it.",
|
|
645
1538
|
cli: "sources update",
|
|
646
1539
|
},
|
|
647
1540
|
},
|
|
@@ -832,10 +1725,23 @@ const codeStandardsStories = [
|
|
|
832
1725
|
// because a pack is data — a future release that drops a label should
|
|
833
1726
|
// degrade to the IRI-derived name, not become unaddressable.
|
|
834
1727
|
//
|
|
835
|
-
// Deliberately NOT declared on `
|
|
836
|
-
// those lists REQUIRES its `by` property, so an entity without
|
|
837
|
-
// row they never publish, and making it addressable (or
|
|
838
|
-
// would be the mirror of the defect this repairs.
|
|
1728
|
+
// Deliberately NOT declared on `token`/`modifier`/`tier`/`concept`:
|
|
1729
|
+
// each of those lists REQUIRES its `by` property, so an entity without
|
|
1730
|
+
// one is a row they never publish, and making it addressable (or
|
|
1731
|
+
// sampleable) here would be the mirror of the defect this repairs.
|
|
1732
|
+
//
|
|
1733
|
+
// `block` is NOT in that set, though an earlier version of this comment
|
|
1734
|
+
// claimed it was: its list COALESCEs an OPTIONAL `ds:name` with an
|
|
1735
|
+
// IRI-derived fallback, so a block without a `ds:name` WOULD be
|
|
1736
|
+
// published under a name its lookup cannot resolve. Every shipped block
|
|
1737
|
+
// carries `ds:name` today, so the divergence is latent — and pinned:
|
|
1738
|
+
// `listLookup.shipped.exec.test.ts` runs the whole corpus through both
|
|
1739
|
+
// halves on every test run, and goes red the moment upstream ships an
|
|
1740
|
+
// unnamed block. Fix it THEN, by choosing deliberately between requiring
|
|
1741
|
+
// the name in the list and declaring a fallback pair whose derivations
|
|
1742
|
+
// actually agree (the list keeps the IRI's dots; the shared
|
|
1743
|
+
// `nameFallback` derivation converts them to slashes — declaring the
|
|
1744
|
+
// fallback alone would trade one mismatch for another).
|
|
839
1745
|
nameFallback: "iri",
|
|
840
1746
|
type: "cs:CodeStandard",
|
|
841
1747
|
description: "Look up one or more standards by name, IRI, or glob. --detail standard adds the dos, --detail detailed adds the don'ts.",
|
|
@@ -938,7 +1844,19 @@ Made by the Canonical Webteam — https://canonical.com.`,
|
|
|
938
1844
|
name: "@canonical/anatomy-dsl",
|
|
939
1845
|
source: "git+https://github.com/canonical/anatomy-dsl.git#main",
|
|
940
1846
|
},
|
|
941
|
-
//
|
|
1847
|
+
// The design-token semantic model: the authored `dt:` / `w3c-tokens:`
|
|
1848
|
+
// ontology in `definitions/` plus the generated strata in `data/`.
|
|
1849
|
+
//
|
|
1850
|
+
// The only source here carrying a SUBDIRECTORY, and it needs one: this
|
|
1851
|
+
// package lives inside a monorepo, at `packages/token-ontology`, while a
|
|
1852
|
+
// git source names a repository. `readTtlSources` scans
|
|
1853
|
+
// `<root>/definitions` and `<root>/data`, which the design-tokens repo
|
|
1854
|
+
// root does not have — so without the subdirectory this would clone
|
|
1855
|
+
// cleanly and contribute nothing.
|
|
1856
|
+
{
|
|
1857
|
+
name: "@canonical/token-ontology",
|
|
1858
|
+
source: "git+https://github.com/canonical/design-tokens.git#main:packages/token-ontology",
|
|
1859
|
+
},
|
|
942
1860
|
// pack an agent is most likely to quote back at a human as policy, so which
|
|
943
1861
|
// revision answered a query has to be recoverable — a floating ref makes
|
|
944
1862
|
// "the CLI told me this was the rule" unfalsifiable. The other three still
|
|
@@ -979,6 +1897,11 @@ Made by the Canonical Webteam — https://canonical.com.`,
|
|
|
979
1897
|
// `cs:` is listed even though nothing rebinds it upstream.
|
|
980
1898
|
prefixes: {
|
|
981
1899
|
ds: "https://ds.canonical.com/",
|
|
1900
|
+
dt: "https://dt.canonical.com/",
|
|
1901
|
+
// Nested UNDER `dt:`, and both must be bound: `compactUri` takes the
|
|
1902
|
+
// longest match, so binding only the parent would render every term of
|
|
1903
|
+
// this vocabulary as `dt:w3c-tokens/…`.
|
|
1904
|
+
"w3c-tokens": "https://dt.canonical.com/w3c-tokens/",
|
|
982
1905
|
cs: "http://pragma.canonical.com/codestandards#",
|
|
983
1906
|
},
|
|
984
1907
|
channel: "normal",
|