@canonical/pragma-cli 0.38.0 → 0.42.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 -3
- package/dist/package.json +16 -16
- package/dist/pragma.conf.js +273 -176
- package/dist/pragma.conf.js.map +1 -1
- package/dist/src/capabilities/capabilities/capabilities.verb.js +2 -0
- package/dist/src/capabilities/capabilities/capabilities.verb.js.map +1 -1
- package/dist/src/capabilities/capabilities/catalog.js +47 -51
- package/dist/src/capabilities/capabilities/catalog.js.map +1 -1
- package/dist/src/capabilities/capabilities/index.js +2 -0
- package/dist/src/capabilities/capabilities/index.js.map +1 -1
- package/dist/src/capabilities/capabilities/types.js +5 -5
- package/dist/src/capabilities/colophon/colophon.render.js +7 -4
- package/dist/src/capabilities/colophon/colophon.render.js.map +1 -1
- package/dist/src/capabilities/colophon/colophon.verb.js +1 -0
- package/dist/src/capabilities/colophon/colophon.verb.js.map +1 -1
- package/dist/src/capabilities/colophon/markdownTerminal.js.map +1 -1
- package/dist/src/capabilities/config/get.verb.js +2 -0
- package/dist/src/capabilities/config/get.verb.js.map +1 -1
- package/dist/src/capabilities/config/runField.js +2 -2
- package/dist/src/capabilities/config/runField.js.map +1 -1
- package/dist/src/capabilities/config/set.verb.js +2 -0
- package/dist/src/capabilities/config/set.verb.js.map +1 -1
- package/dist/src/capabilities/config/show.render.js.map +1 -1
- package/dist/src/capabilities/config/show.verb.js +1 -0
- package/dist/src/capabilities/config/show.verb.js.map +1 -1
- package/dist/src/capabilities/config/unset.verb.js +2 -0
- package/dist/src/capabilities/config/unset.verb.js.map +1 -1
- package/dist/src/capabilities/create/constants.js +8 -5
- package/dist/src/capabilities/create/constants.js.map +1 -1
- package/dist/src/capabilities/create/create.render.js.map +1 -1
- package/dist/src/capabilities/create/create.verb.js +36 -7
- package/dist/src/capabilities/create/create.verb.js.map +1 -1
- package/dist/src/capabilities/create/createSurface.generated.js +22 -0
- package/dist/src/capabilities/create/createSurface.generated.js.map +1 -1
- package/dist/src/capabilities/create/index.js +1 -1
- package/dist/src/capabilities/create/pickGenerator.js +1 -0
- package/dist/src/capabilities/create/pickGenerator.js.map +1 -1
- package/dist/src/capabilities/distribution.js +3 -1
- package/dist/src/capabilities/distribution.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/checkPackageRefs.js +10 -2
- package/dist/src/capabilities/doctor/checks/checkPackageRefs.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
- package/dist/src/capabilities/doctor/doctor.verb.js +2 -0
- package/dist/src/capabilities/doctor/doctor.verb.js.map +1 -1
- package/dist/src/capabilities/graph/connect.verb.js +2 -0
- package/dist/src/capabilities/graph/connect.verb.js.map +1 -1
- package/dist/src/capabilities/graph/inspect.render.js +7 -1
- package/dist/src/capabilities/graph/inspect.render.js.map +1 -1
- package/dist/src/capabilities/graph/inspect.verb.js +2 -0
- package/dist/src/capabilities/graph/inspect.verb.js.map +1 -1
- package/dist/src/capabilities/graph/query.render.js +37 -5
- package/dist/src/capabilities/graph/query.render.js.map +1 -1
- package/dist/src/capabilities/graph/query.verb.js +2 -0
- package/dist/src/capabilities/graph/query.verb.js.map +1 -1
- package/dist/src/capabilities/graph/queryText.js +28 -0
- package/dist/src/capabilities/graph/queryText.js.map +1 -1
- package/dist/src/capabilities/graph/runConnect.js +3 -3
- package/dist/src/capabilities/graph/runConnect.js.map +1 -1
- package/dist/src/capabilities/graph/runQuery.js +8 -6
- package/dist/src/capabilities/graph/runQuery.js.map +1 -1
- package/dist/src/capabilities/info/info.verb.js +2 -0
- package/dist/src/capabilities/info/info.verb.js.map +1 -1
- package/dist/src/capabilities/meta/mcp.verb.js +1 -0
- package/dist/src/capabilities/meta/mcp.verb.js.map +1 -1
- package/dist/src/capabilities/ontology/verbs.js +7 -10
- package/dist/src/capabilities/ontology/verbs.js.map +1 -1
- package/dist/src/capabilities/prompt/verbs.js +5 -4
- package/dist/src/capabilities/prompt/verbs.js.map +1 -1
- package/dist/src/capabilities/resources/provider.js +6 -3
- package/dist/src/capabilities/resources/provider.js.map +1 -1
- package/dist/src/capabilities/setup/operations/writability.js.map +1 -1
- package/dist/src/capabilities/setup/plan.render.js.map +1 -1
- package/dist/src/capabilities/setup/setup.verb.js +13 -5
- package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
- package/dist/src/capabilities/shared/calls.js +16 -0
- package/dist/src/capabilities/shared/calls.js.map +1 -0
- package/dist/src/capabilities/shared/packageManager.js.map +1 -1
- package/dist/src/capabilities/skill/discover.js.map +1 -1
- package/dist/src/capabilities/skill/render.js +7 -5
- package/dist/src/capabilities/skill/render.js.map +1 -1
- package/dist/src/capabilities/skill/verbs.js +5 -4
- package/dist/src/capabilities/skill/verbs.js.map +1 -1
- package/dist/src/capabilities/sources/collectStatus.js +6 -1
- package/dist/src/capabilities/sources/collectStatus.js.map +1 -1
- package/dist/src/capabilities/sources/index.js +4 -3
- package/dist/src/capabilities/sources/index.js.map +1 -1
- package/dist/src/capabilities/sources/reset.render.js +37 -0
- package/dist/src/capabilities/sources/reset.render.js.map +1 -0
- package/dist/src/capabilities/sources/reset.verb.js +51 -0
- package/dist/src/capabilities/sources/reset.verb.js.map +1 -0
- package/dist/src/capabilities/sources/runReset.js +59 -0
- package/dist/src/capabilities/sources/runReset.js.map +1 -0
- package/dist/src/capabilities/sources/runUpdate.js +7 -6
- package/dist/src/capabilities/sources/runUpdate.js.map +1 -1
- package/dist/src/capabilities/sources/status.render.js +24 -8
- package/dist/src/capabilities/sources/status.render.js.map +1 -1
- package/dist/src/capabilities/sources/status.verb.js +1 -0
- package/dist/src/capabilities/sources/status.verb.js.map +1 -1
- package/dist/src/capabilities/sources/update.verb.js +2 -0
- package/dist/src/capabilities/sources/update.verb.js.map +1 -1
- package/dist/src/capabilities/upgrade/upgrade.verb.js +1 -0
- package/dist/src/capabilities/upgrade/upgrade.verb.js.map +1 -1
- package/dist/src/capabilities/version/version.verb.js +1 -0
- package/dist/src/capabilities/version/version.verb.js.map +1 -1
- package/dist/src/constants.js +4 -3
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernel/completion/complete.js.map +1 -1
- package/dist/src/kernel/completion/emitScripts.js.map +1 -1
- package/dist/src/kernel/completion/parse.js.map +1 -1
- package/dist/src/kernel/completion/rank.js.map +1 -1
- package/dist/src/kernel/completion/resolve.js.map +1 -1
- package/dist/src/kernel/config/readConfig.js.map +1 -1
- package/dist/src/kernel/error/PragmaError.js.map +1 -1
- package/dist/src/kernel/error/index.js +1 -1
- package/dist/src/kernel/error/index.js.map +1 -1
- package/dist/src/kernel/error/recovery.js +24 -42
- package/dist/src/kernel/error/recovery.js.map +1 -1
- package/dist/src/kernel/packs/collect.js +123 -9
- package/dist/src/kernel/packs/collect.js.map +1 -1
- package/dist/src/kernel/packs/compile.js +74 -15
- package/dist/src/kernel/packs/compile.js.map +1 -1
- package/dist/src/kernel/packs/graphql/fetchGraphqlLookup.js +3 -3
- package/dist/src/kernel/packs/graphql/fetchGraphqlLookup.js.map +1 -1
- package/dist/src/kernel/packs/iri.js +2 -4
- package/dist/src/kernel/packs/iri.js.map +1 -1
- package/dist/src/kernel/packs/renderPack.js +90 -50
- package/dist/src/kernel/packs/renderPack.js.map +1 -1
- package/dist/src/kernel/packs/resolveEntity.js +202 -90
- package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
- package/dist/src/kernel/packs/runBodies.js +89 -30
- package/dist/src/kernel/packs/runBodies.js.map +1 -1
- package/dist/src/kernel/packs/schema.js +66 -12
- package/dist/src/kernel/packs/schema.js.map +1 -1
- package/dist/src/kernel/packs/sparql/buildListQuery.js +80 -13
- package/dist/src/kernel/packs/sparql/buildListQuery.js.map +1 -1
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js +41 -13
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
- package/dist/src/kernel/packs/sparql/filterValues.js +32 -23
- package/dist/src/kernel/packs/sparql/filterValues.js.map +1 -1
- package/dist/src/kernel/packs/sparql/runSelect.js +3 -5
- package/dist/src/kernel/packs/sparql/runSelect.js.map +1 -1
- package/dist/src/kernel/packs/storyRules.js +31 -4
- package/dist/src/kernel/packs/storyRules.js.map +1 -1
- package/dist/src/kernel/packs/tierScope.js +3 -3
- package/dist/src/kernel/packs/tierScope.js.map +1 -1
- package/dist/src/kernel/packs/types.js +4 -0
- package/dist/src/kernel/packs/types.js.map +1 -1
- package/dist/src/kernel/project/cli/buildProgram.js +4 -0
- package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
- package/dist/src/kernel/project/cli/dispatch.js +32 -8
- package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
- package/dist/src/kernel/project/cli/globalFlags.js.map +1 -1
- package/dist/src/kernel/project/cli/suggestNames.js +44 -1
- package/dist/src/kernel/project/cli/suggestNames.js.map +1 -1
- package/dist/src/kernel/project/cli/verbHelp.js +17 -18
- package/dist/src/kernel/project/cli/verbHelp.js.map +1 -1
- package/dist/src/kernel/project/mcp/buildServer.js +11 -4
- package/dist/src/kernel/project/mcp/buildServer.js.map +1 -1
- package/dist/src/kernel/project/mcp/envelope.js +3 -2
- package/dist/src/kernel/project/mcp/envelope.js.map +1 -1
- package/dist/src/kernel/project/mcp/instructions.js +101 -31
- package/dist/src/kernel/project/mcp/instructions.js.map +1 -1
- package/dist/src/kernel/project/mcp/registerVerb.js +59 -23
- package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
- package/dist/src/kernel/render/envelope.js.map +1 -1
- package/dist/src/kernel/render/renderers.js +3 -3
- package/dist/src/kernel/render/renderers.js.map +1 -1
- package/dist/src/kernel/render/turtle.js +21 -4
- package/dist/src/kernel/render/turtle.js.map +1 -1
- package/dist/src/kernel/runtime/boot.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/build.js +54 -1
- package/dist/src/kernel/runtime/graphpack/build.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/manifest.js +14 -0
- package/dist/src/kernel/runtime/graphpack/manifest.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/read.js +3 -5
- package/dist/src/kernel/runtime/graphpack/read.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/schemas.js +1 -0
- package/dist/src/kernel/runtime/graphpack/schemas.js.map +1 -1
- package/dist/src/kernel/runtime/loadSession.js +8 -1
- package/dist/src/kernel/runtime/loadSession.js.map +1 -1
- package/dist/src/kernel/runtime/packVersion.js +75 -0
- package/dist/src/kernel/runtime/packVersion.js.map +1 -0
- package/dist/src/kernel/runtime/readEntity.js +43 -4
- package/dist/src/kernel/runtime/readEntity.js.map +1 -1
- package/dist/src/kernel/runtime/refs/resolve.js.map +1 -1
- package/dist/src/kernel/runtime/resolveSources.js +61 -9
- package/dist/src/kernel/runtime/resolveSources.js.map +1 -1
- package/dist/src/kernel/runtime/storeReadiness.js +3 -2
- package/dist/src/kernel/runtime/storeReadiness.js.map +1 -1
- package/dist/src/kernel/spec/call.js +167 -0
- package/dist/src/kernel/spec/call.js.map +1 -0
- package/dist/src/kernel/spec/emitReference.js +9 -13
- package/dist/src/kernel/spec/emitReference.js.map +1 -1
- package/dist/src/kernel/spec/emitSurface.js +8 -1
- package/dist/src/kernel/spec/emitSurface.js.map +1 -1
- package/dist/src/kernel/spec/guidance.js +63 -0
- package/dist/src/kernel/spec/guidance.js.map +1 -0
- package/dist/src/kernel/spec/wireType.js +36 -0
- package/dist/src/kernel/spec/wireType.js.map +1 -0
- package/package.json +16 -16
- package/pragma.conf.ts +294 -177
- package/src/capabilities/block.parity.test.ts +1 -1
- package/src/capabilities/callRule.test.ts +147 -0
- package/src/capabilities/capabilities/capabilities.test.ts +47 -19
- package/src/capabilities/capabilities/capabilities.verb.ts +2 -0
- package/src/capabilities/capabilities/catalog.ts +60 -55
- package/src/capabilities/capabilities/index.ts +2 -0
- package/src/capabilities/capabilities/types.ts +16 -19
- package/src/capabilities/colophon/colophon.render.ts +9 -5
- package/src/capabilities/colophon/colophon.verb.ts +1 -0
- package/src/capabilities/config/get.verb.ts +2 -0
- package/src/capabilities/config/runField.ts +3 -3
- package/src/capabilities/config/set.verb.ts +3 -0
- package/src/capabilities/config/show.verb.ts +2 -0
- package/src/capabilities/config/unset.verb.ts +2 -0
- package/src/capabilities/create/constants.ts +8 -5
- package/src/capabilities/create/create.mcp.test.ts +173 -1
- package/src/capabilities/create/create.test.ts +4 -2
- package/src/capabilities/create/create.verb.ts +45 -3
- package/src/capabilities/create/createGrammar.test.ts +41 -5
- package/src/capabilities/create/createSurface.generated.ts +22 -0
- package/src/capabilities/create/crossCli.subprocess.test.ts +53 -14
- package/src/capabilities/create/index.ts +1 -1
- package/src/capabilities/create/pickGenerator.ts +1 -0
- package/src/capabilities/create/shippedCreate.subprocess.test.ts +28 -7
- package/src/capabilities/distribution.test.ts +6 -3
- package/src/capabilities/distribution.ts +6 -0
- package/src/capabilities/doctor/checks/checkPackageRefs.ts +14 -2
- package/src/capabilities/doctor/doctor.test.ts +38 -1
- package/src/capabilities/doctor/doctor.verb.ts +2 -0
- package/src/capabilities/emptyRecovery.test.ts +5 -0
- package/src/capabilities/graph/connect.verb.ts +2 -0
- package/src/capabilities/graph/inspect.render.ts +9 -1
- package/src/capabilities/graph/inspect.test.ts +73 -0
- package/src/capabilities/graph/inspect.verb.ts +2 -0
- package/src/capabilities/graph/query.render.test.ts +35 -0
- package/src/capabilities/graph/query.render.ts +45 -7
- package/src/capabilities/graph/query.shipped.exec.test.ts +44 -0
- package/src/capabilities/graph/query.verb.ts +2 -0
- package/src/capabilities/graph/queryText.test.ts +55 -1
- package/src/capabilities/graph/queryText.ts +47 -0
- package/src/capabilities/graph/runConnect.ts +4 -5
- package/src/capabilities/graph/runQuery.ts +23 -9
- package/src/capabilities/info/info.verb.ts +2 -0
- package/src/capabilities/links.shipped.exec.test.ts +398 -0
- package/src/capabilities/listBudget.shipped.exec.test.ts +2 -2
- package/src/capabilities/listLookup.shipped.exec.test.ts +122 -13
- package/src/capabilities/listQuery.shipped.exec.test.ts +39 -16
- package/src/capabilities/lookupBudget.shipped.exec.test.ts +208 -0
- package/src/capabilities/meta/mcp.verb.ts +2 -0
- package/src/capabilities/ontology/ontology.test.ts +24 -0
- package/src/capabilities/ontology/verbs.ts +16 -12
- package/src/capabilities/prompt/verbs.ts +10 -4
- package/src/capabilities/resources/provider.ts +7 -3
- package/src/capabilities/resources/resources.test.ts +2 -1
- package/src/capabilities/setup/setup.verb.ts +16 -0
- package/src/capabilities/shared/calls.ts +20 -0
- package/src/capabilities/skill/render.ts +9 -6
- package/src/capabilities/skill/verbs.ts +8 -4
- package/src/capabilities/sources/collectStatus.ts +6 -1
- package/src/capabilities/sources/index.ts +4 -3
- package/src/capabilities/sources/reset.render.test.ts +33 -0
- package/src/capabilities/sources/reset.render.ts +43 -0
- package/src/capabilities/sources/reset.verb.ts +59 -0
- package/src/capabilities/sources/runReset.ts +65 -0
- package/src/capabilities/sources/runUpdate.ts +12 -11
- package/src/capabilities/sources/sources.test.ts +158 -3
- package/src/capabilities/sources/status.render.test.ts +63 -1
- package/src/capabilities/sources/status.render.ts +25 -8
- package/src/capabilities/sources/status.verb.ts +2 -0
- package/src/capabilities/sources/types.ts +26 -0
- package/src/capabilities/sources/update.verb.ts +3 -0
- package/src/capabilities/surface.test.ts +29 -4
- package/src/capabilities/token.parity.test.ts +3 -2
- package/src/capabilities/tokenGraph.shipped.exec.test.ts +14 -2
- package/src/capabilities/upgrade/upgrade.verb.ts +1 -0
- package/src/capabilities/variable.parity.test.ts +2 -1
- package/src/capabilities/version/version.verb.ts +1 -0
- package/src/capabilities/wireContract.test.ts +110 -0
- package/src/constants.ts +4 -3
- package/src/kernel/completion/shellDrive.test.ts +2 -2
- package/src/kernel/copy.test.ts +1 -1
- package/src/kernel/error/PragmaError.test.ts +7 -3
- package/src/kernel/error/index.ts +1 -1
- package/src/kernel/error/recovery.test.ts +52 -18
- package/src/kernel/error/recovery.ts +25 -46
- package/src/kernel/error/types.ts +1 -1
- package/src/kernel/packs/collect.test.ts +79 -0
- package/src/kernel/packs/collect.ts +151 -11
- package/src/kernel/packs/compile.test.ts +107 -10
- package/src/kernel/packs/compile.ts +100 -11
- package/src/kernel/packs/filteredEmpty.test.ts +22 -5
- package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +5 -6
- package/src/kernel/packs/graphqlSource.test.ts +42 -0
- package/src/kernel/packs/iri.ts +5 -4
- package/src/kernel/packs/listNotice.test.ts +1 -1
- package/src/kernel/packs/nounLink.test.ts +385 -0
- package/src/kernel/packs/renderPack.ts +137 -57
- package/src/kernel/packs/resolveEntity.test.ts +170 -1
- package/src/kernel/packs/resolveEntity.ts +281 -101
- package/src/kernel/packs/runBodies.ts +133 -31
- package/src/kernel/packs/schema.ts +77 -12
- package/src/kernel/packs/sparql/buildListQuery.test.ts +78 -1
- package/src/kernel/packs/sparql/buildListQuery.ts +106 -16
- package/src/kernel/packs/sparql/buildLookupQuery.ts +44 -13
- package/src/kernel/packs/sparql/filterValues.test.ts +36 -4
- package/src/kernel/packs/sparql/filterValues.ts +50 -31
- package/src/kernel/packs/sparql/runSelect.ts +4 -6
- package/src/kernel/packs/storyRules.ts +37 -4
- package/src/kernel/packs/tierScope.test.ts +120 -6
- package/src/kernel/packs/tierScope.ts +5 -7
- package/src/kernel/packs/toolDescription.test.ts +59 -74
- package/src/kernel/packs/types.ts +93 -11
- package/src/kernel/project/cli/buildProgram.ts +4 -0
- package/src/kernel/project/cli/dispatch.ts +34 -8
- package/src/kernel/project/cli/suggest.test.ts +77 -0
- package/src/kernel/project/cli/suggestNames.ts +47 -1
- package/src/kernel/project/cli/verbHelp.ts +16 -19
- package/src/kernel/project/mcp/buildServer.ts +15 -4
- package/src/kernel/project/mcp/envelope.ts +3 -2
- package/src/kernel/project/mcp/instructions.ts +123 -35
- package/src/kernel/project/mcp/prompts/prompts.test.ts +136 -20
- package/src/kernel/project/mcp/registerVerb.test.ts +28 -0
- package/src/kernel/project/mcp/registerVerb.ts +67 -29
- package/src/kernel/render/__snapshots__/renderers.test.ts.snap +1 -1
- package/src/kernel/render/renderers.test.ts +2 -2
- package/src/kernel/render/renderers.ts +3 -3
- package/src/kernel/render/turtle.ts +24 -4
- package/src/kernel/runtime/graphpack/build.ts +58 -1
- package/src/kernel/runtime/graphpack/graphpack.test.ts +20 -0
- package/src/kernel/runtime/graphpack/manifest.ts +15 -0
- package/src/kernel/runtime/graphpack/read.ts +4 -6
- package/src/kernel/runtime/graphpack/schemas.ts +1 -0
- package/src/kernel/runtime/graphpack/types.ts +13 -0
- package/src/kernel/runtime/loadSession.ts +8 -1
- package/src/kernel/runtime/packVersion.test.ts +61 -0
- package/src/kernel/runtime/packVersion.ts +84 -0
- package/src/kernel/runtime/readEntity.ts +61 -6
- package/src/kernel/runtime/resolveSources.test.ts +90 -7
- package/src/kernel/runtime/resolveSources.ts +91 -10
- package/src/kernel/runtime/storeReadiness.ts +4 -4
- package/src/kernel/runtime/types.ts +12 -0
- package/src/kernel/spec/call.test.ts +95 -0
- package/src/kernel/spec/call.ts +186 -0
- package/src/kernel/spec/emitReference.ts +9 -13
- package/src/kernel/spec/emitSurface.ts +9 -1
- package/src/kernel/spec/guidance.test.ts +49 -0
- package/src/kernel/spec/guidance.ts +68 -0
- package/src/kernel/spec/index.ts +4 -0
- package/src/kernel/spec/surfaceConformance.test.ts +2 -2
- package/src/kernel/spec/types.ts +64 -7
- package/src/kernel/spec/wireType.ts +53 -0
- package/src/testing/behavioral/README.md +1 -1
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +2 -1
- package/src/testing/behavioral/journeys.firstInstall.test.ts +72 -2
- package/src/testing/behavioral/parity.test.ts +40 -0
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +1 -1
- package/src/testing/eval/cases/assembly.ts +4 -3
- package/src/testing/eval/cases/stable.ts +2 -3
- package/src/testing/helpers/callSchema.ts +40 -0
- package/src/testing/helpers/parity.ts +35 -2
- package/src/testing/setupCallChecking.ts +30 -0
- package/dist/src/capabilities/capabilities/hints.js +0 -223
- package/dist/src/capabilities/capabilities/hints.js.map +0 -1
- package/src/capabilities/capabilities/hints.ts +0 -266
|
@@ -58,7 +58,7 @@ ex:slider a ex:Widget ; ex:name "Slider" ; ex:kind "input" .
|
|
|
58
58
|
const EMPTY_RECOVERY = {
|
|
59
59
|
message:
|
|
60
60
|
"Widgets are recorded by the catalogue build, and a store built before it ran records none.",
|
|
61
|
-
|
|
61
|
+
call: { verb: "sources update" },
|
|
62
62
|
} as const;
|
|
63
63
|
|
|
64
64
|
const listShape = (uriClass: string) => ({
|
|
@@ -133,10 +133,12 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
|
|
|
133
133
|
expect(outcome.exitCode).toBe(0);
|
|
134
134
|
const said = `${outcome.stdout ?? ""}${outcome.stderr ?? ""}`;
|
|
135
135
|
expect(said).toContain("No widget matches `--search zzzznotreal`.");
|
|
136
|
-
// The filter is the news; the story's account of where
|
|
137
|
-
//
|
|
136
|
+
// The filter is the news, with how to widen; the story's account of where
|
|
137
|
+
// widgets come from is kept — and the rebuild is not advised, because a
|
|
138
|
+
// filter that missed says nothing about the store.
|
|
139
|
+
expect(said).toContain("drop the argument, or loosen it");
|
|
138
140
|
expect(said).toContain("recorded by the catalogue build");
|
|
139
|
-
expect(said).toContain("
|
|
141
|
+
expect(said).not.toContain("sources update");
|
|
140
142
|
});
|
|
141
143
|
|
|
142
144
|
it("every filter in force is named", async () => {
|
|
@@ -195,7 +197,7 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
|
|
|
195
197
|
const said = `${outcome.stderr ?? ""}`;
|
|
196
198
|
expect(said).toContain("No gadget matches `--kind input`.");
|
|
197
199
|
expect(said).toContain("recorded by the catalogue build");
|
|
198
|
-
expect(said).toContain("
|
|
200
|
+
expect(said).not.toContain("sources update");
|
|
199
201
|
});
|
|
200
202
|
|
|
201
203
|
it("an EMPTY POPULATION unfiltered gets the kernel's own sentence", async () => {
|
|
@@ -210,4 +212,19 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
|
|
|
210
212
|
expect(outcome.stderr).toContain("recorded by the catalogue build");
|
|
211
213
|
expect(outcome.stderr).toContain("pragma sources update");
|
|
212
214
|
});
|
|
215
|
+
|
|
216
|
+
it("a story with no recovery of its own: rebuild unfiltered, never when filtered", async () => {
|
|
217
|
+
const bare: PackDefinition = {
|
|
218
|
+
...GADGET_PACK,
|
|
219
|
+
list: { ...listShape("ex:Gadget") },
|
|
220
|
+
};
|
|
221
|
+
const said = async (params: Record<string, unknown>): Promise<string> =>
|
|
222
|
+
(await executeVerb(listVerb(bare), params, REAL, as(PLAIN))).stderr ?? "";
|
|
223
|
+
|
|
224
|
+
expect(await said({})).toContain("pragma sources update");
|
|
225
|
+
const filtered = await said({ kind: "input" });
|
|
226
|
+
expect(filtered).toContain("drop the argument, or loosen it");
|
|
227
|
+
expect(filtered).not.toContain("sources update");
|
|
228
|
+
expect(filtered).not.toContain("needs building");
|
|
229
|
+
});
|
|
213
230
|
});
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* composed only from validated pack terms and compiled schema names.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { callRecovery, PragmaError } from "../../error/index.js";
|
|
18
18
|
import type { PragmaRuntime } from "../../runtime/index.js";
|
|
19
19
|
import type { PackChildRow, PackEntity, PackLookup } from "../types.js";
|
|
20
20
|
import {
|
|
@@ -56,10 +56,9 @@ export async function fetchGraphqlLookup(
|
|
|
56
56
|
.join("; ");
|
|
57
57
|
throw PragmaError.storeUnavailable(`GraphQL lookup failed: ${messages}`, {
|
|
58
58
|
// `graph inspect` needs a <uri>; `ontology list` is runnable as-is.
|
|
59
|
-
recovery:
|
|
60
|
-
"ontology list",
|
|
59
|
+
recovery: callRecovery(
|
|
60
|
+
{ verb: "ontology list" },
|
|
61
61
|
"Check the loaded ontology and namespaces.",
|
|
62
|
-
{ tool: "ontology_list" },
|
|
63
62
|
),
|
|
64
63
|
});
|
|
65
64
|
}
|
|
@@ -72,8 +71,8 @@ export async function fetchGraphqlLookup(
|
|
|
72
71
|
throw new PragmaError({
|
|
73
72
|
code: "ENTITY_NOT_FOUND",
|
|
74
73
|
message: `Cannot resolve <${entityUri}> — its rdf:type may be missing from the ontology.`,
|
|
75
|
-
recovery:
|
|
76
|
-
|
|
74
|
+
recovery: callRecovery(
|
|
75
|
+
{ verb: "graph inspect", params: { uri: entityUri } },
|
|
77
76
|
"Inspect the entity's triples to check its rdf:type.",
|
|
78
77
|
),
|
|
79
78
|
});
|
|
@@ -14,6 +14,7 @@ import { buildFixtureRuntime } from "../../testing/helpers/packRuntime.js";
|
|
|
14
14
|
import type { PragmaRuntime, StoreSession } from "../runtime/types.js";
|
|
15
15
|
import { compilePack } from "./compile.js";
|
|
16
16
|
import { buildLookupDocument } from "./graphql/buildLookupDocument.js";
|
|
17
|
+
import { fetchGraphqlLookup } from "./graphql/fetchGraphqlLookup.js";
|
|
17
18
|
import type { LookupOutput } from "./resolveEntity.js";
|
|
18
19
|
import { parsePackDefinition } from "./schema.js";
|
|
19
20
|
import type { PackDefinition, PackLookup } from "./types.js";
|
|
@@ -320,6 +321,47 @@ describe("GraphQL engine — against the compiled fixture schema (PROTECTED)", (
|
|
|
320
321
|
|
|
321
322
|
const lookup = GBLOCK.lookup as PackLookup;
|
|
322
323
|
|
|
324
|
+
/** The fixture runtime with its GraphQL executor replaced by a canned answer. */
|
|
325
|
+
const answering = (answer: unknown): PragmaRuntime =>
|
|
326
|
+
({
|
|
327
|
+
...rt,
|
|
328
|
+
query: { ...rt.query, graphql: async () => answer },
|
|
329
|
+
}) as PragmaRuntime;
|
|
330
|
+
const fetchWith = (answer: unknown) =>
|
|
331
|
+
fetchGraphqlLookup(
|
|
332
|
+
answering(answer),
|
|
333
|
+
lookup,
|
|
334
|
+
"https://ds.canonical.com/x",
|
|
335
|
+
"X",
|
|
336
|
+
"t",
|
|
337
|
+
BLOCK_PREFIXES,
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
it("an execution error recovers to the namespace list, in both spellings", async () => {
|
|
341
|
+
await expect(
|
|
342
|
+
fetchWith({ errors: [{ message: "boom" }] }),
|
|
343
|
+
).rejects.toMatchObject({
|
|
344
|
+
code: "STORE_UNAVAILABLE",
|
|
345
|
+
recovery: {
|
|
346
|
+
cli: "pragma ontology list",
|
|
347
|
+
mcp: { tool: "ontology_list", params: {} },
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it("a resolved IRI with no typed node recovers to inspecting THAT entity", async () => {
|
|
353
|
+
await expect(fetchWith({ data: { node: null } })).rejects.toMatchObject({
|
|
354
|
+
code: "ENTITY_NOT_FOUND",
|
|
355
|
+
recovery: {
|
|
356
|
+
cli: "pragma graph inspect https://ds.canonical.com/x",
|
|
357
|
+
mcp: {
|
|
358
|
+
tool: "graph_inspect",
|
|
359
|
+
params: { uri: "https://ds.canonical.com/x" },
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
323
365
|
it("generates one document with derived names, Relay envelopes, subtype scoping", () => {
|
|
324
366
|
const plan = buildLookupDocument(lookup, schema, "t");
|
|
325
367
|
expect(plan.source).toContain("query PackLookup($uri: ID!)");
|
package/src/kernel/packs/iri.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* before it can be interpolated into a generated `<iri>` query token.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { callRecovery, PragmaError } from "../error/index.js";
|
|
11
11
|
|
|
12
12
|
/** Characters not allowed inside a SPARQL `<IRI>`. */
|
|
13
13
|
const UNSAFE_IRI_PATTERN = /[<>"{}|\\^`\s]/;
|
|
@@ -86,9 +86,10 @@ function tryResolveUri(
|
|
|
86
86
|
|
|
87
87
|
return PragmaError.invalidInput("prefix", prefix, {
|
|
88
88
|
validOptions: Object.keys(prefixes),
|
|
89
|
-
recovery:
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
recovery: callRecovery(
|
|
90
|
+
{ verb: "ontology list" },
|
|
91
|
+
"List known ontology prefixes.",
|
|
92
|
+
),
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -46,7 +46,7 @@ ex:slider a ex:Widget ; ex:name "Slider" ; ex:kind "input" .
|
|
|
46
46
|
/** The recovery a story authors for an EMPTY POPULATION — never for a filter. */
|
|
47
47
|
const EMPTY_RECOVERY = {
|
|
48
48
|
message: "No widgets in the store.",
|
|
49
|
-
|
|
49
|
+
call: { verb: "sources update" },
|
|
50
50
|
} as const;
|
|
51
51
|
|
|
52
52
|
const WIDGET_LIST = {
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A filter that names a noun accepts what that noun's lookup accepts, and a
|
|
3
|
+
* `many` expand field adds values to a row, never rows.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
7
|
+
import { buildFixtureRuntime } from "../../testing/helpers/packRuntime.js";
|
|
8
|
+
import type { ConfigLayers } from "../config/index.js";
|
|
9
|
+
import type { PragmaRuntime } from "../runtime/types.js";
|
|
10
|
+
import type { CapabilityModule, VerbSpec } from "../spec/types.js";
|
|
11
|
+
import { assembleEffectiveModules, screenPackageStories } from "./collect.js";
|
|
12
|
+
import { compilePack, compileStoryModule } from "./compile.js";
|
|
13
|
+
import type { LookupOutput } from "./resolveEntity.js";
|
|
14
|
+
import { parsePackDefinition } from "./schema.js";
|
|
15
|
+
import {
|
|
16
|
+
distributionSource,
|
|
17
|
+
type PackDefinition,
|
|
18
|
+
type PackPage,
|
|
19
|
+
} from "./types.js";
|
|
20
|
+
import { verbKey } from "./uniqueness.js";
|
|
21
|
+
|
|
22
|
+
const PREFIXES = {
|
|
23
|
+
ex: "https://example.org/shop#",
|
|
24
|
+
owl: "http://www.w3.org/2002/07/owl#",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const TTL = `
|
|
28
|
+
@prefix ex: <https://example.org/shop#> .
|
|
29
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
30
|
+
|
|
31
|
+
ex:Maker a owl:Class .
|
|
32
|
+
ex:Widget a owl:Class .
|
|
33
|
+
|
|
34
|
+
ex:acme a ex:Maker ; ex:name "Acme" ; ex:code "A1" .
|
|
35
|
+
ex:acme2 a ex:Maker ; ex:name "Acme" .
|
|
36
|
+
ex:bolt a ex:Maker ; ex:name "Bolt" .
|
|
37
|
+
ex:idle a ex:Maker ; ex:name "Idle" .
|
|
38
|
+
|
|
39
|
+
ex:button a ex:Widget ; ex:name "Button" ; ex:madeBy ex:acme ;
|
|
40
|
+
ex:alias "btn" , "Btn" , "push-button" .
|
|
41
|
+
ex:label a ex:Widget ; ex:name "Label" ; ex:madeBy ex:acme2 .
|
|
42
|
+
ex:slider a ex:Widget ; ex:name "Slider" ; ex:madeBy ex:bolt .
|
|
43
|
+
|
|
44
|
+
ex:bolt ex:part
|
|
45
|
+
[ ex:group "g" ; ex:label "f" ; ex:tag "x" , "y" ] ,
|
|
46
|
+
[ ex:group "g" ; ex:label "c" ; ex:tag "x" ] ,
|
|
47
|
+
[ ex:group "g" ; ex:label "e" ] ,
|
|
48
|
+
[ ex:group "g" ; ex:label "a" ; ex:tag "y" ] ,
|
|
49
|
+
[ ex:group "g" ; ex:label "d" ; ex:tag "x" ] ,
|
|
50
|
+
[ ex:group "g" ; ex:label "b" ] .
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
const MAKER: PackDefinition = {
|
|
54
|
+
noun: "maker",
|
|
55
|
+
lookup: {
|
|
56
|
+
by: "ex:name",
|
|
57
|
+
type: "ex:Maker",
|
|
58
|
+
expand: [
|
|
59
|
+
{
|
|
60
|
+
name: "widgets",
|
|
61
|
+
kind: "table",
|
|
62
|
+
relation: "^ex:madeBy",
|
|
63
|
+
select: [
|
|
64
|
+
{ name: "name", property: "ex:name", noun: "widget" },
|
|
65
|
+
{ name: "aliases", property: "ex:alias", many: true },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "parts",
|
|
70
|
+
kind: "table",
|
|
71
|
+
relation: "ex:part",
|
|
72
|
+
// Every part ties on the one declared key.
|
|
73
|
+
orderBy: ["group"],
|
|
74
|
+
select: [
|
|
75
|
+
{ name: "group", property: "ex:group" },
|
|
76
|
+
{ name: "label", property: "ex:label" },
|
|
77
|
+
{ name: "tags", property: "ex:tag", many: true },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const WIDGET: PackDefinition = {
|
|
85
|
+
noun: "widget",
|
|
86
|
+
list: {
|
|
87
|
+
query: [
|
|
88
|
+
"SELECT ?uri ?name ?maker ?makerUri WHERE {",
|
|
89
|
+
" ?uri a ex:Widget ; ex:name ?name ; ex:madeBy ?makerUri .",
|
|
90
|
+
" ?makerUri ex:name ?maker .",
|
|
91
|
+
"} ORDER BY ?name",
|
|
92
|
+
].join("\n"),
|
|
93
|
+
columns: [
|
|
94
|
+
{ field: "name", label: "Name" },
|
|
95
|
+
{ field: "maker", label: "Maker", noun: "maker" },
|
|
96
|
+
],
|
|
97
|
+
filters: [
|
|
98
|
+
{ param: "maker", variable: "maker", noun: "maker", entity: "makerUri" },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
lookup: { by: "ex:name", type: "ex:Widget" },
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const STORIES = new Map([MAKER, WIDGET].map((story) => [story.noun, story]));
|
|
105
|
+
|
|
106
|
+
const verb = (story: PackDefinition, name: string): VerbSpec =>
|
|
107
|
+
compilePack(
|
|
108
|
+
story,
|
|
109
|
+
distributionSource("test:links"),
|
|
110
|
+
PREFIXES,
|
|
111
|
+
(noun) => STORIES.get(noun)?.lookup,
|
|
112
|
+
).find((v) => verbKey(v.path) === `${story.noun} ${name}`) as VerbSpec;
|
|
113
|
+
|
|
114
|
+
let rt: PragmaRuntime;
|
|
115
|
+
beforeAll(async () => {
|
|
116
|
+
({ rt } = await buildFixtureRuntime({ ttl: TTL, prefixes: PREFIXES }));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const widgetsBy = async (maker: unknown): Promise<PackPage["rows"]> =>
|
|
120
|
+
((await verb(WIDGET, "list").run({ maker }, rt)) as PackPage).rows;
|
|
121
|
+
|
|
122
|
+
describe("a filter that names a noun", () => {
|
|
123
|
+
it("takes a name, and a shared name means every entity it reaches", async () => {
|
|
124
|
+
const rows = await widgetsBy("acme");
|
|
125
|
+
expect(rows.map((row) => row.name)).toEqual(["Button", "Label"]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("takes a prefixed IRI and an absolute IRI, which reach one entity", async () => {
|
|
129
|
+
expect((await widgetsBy("ex:acme2")).map((row) => row.name)).toEqual([
|
|
130
|
+
"Label",
|
|
131
|
+
]);
|
|
132
|
+
expect(
|
|
133
|
+
(await widgetsBy("https://example.org/shop#bolt")).map((row) => row.name),
|
|
134
|
+
).toEqual(["Slider"]);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("takes several values as a union", async () => {
|
|
138
|
+
const rows = await widgetsBy(["Bolt", "ex:acme"]);
|
|
139
|
+
expect(rows.map((row) => row.name)).toEqual(["Button", "Slider"]);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("leaves the entity variable out of the rows", async () => {
|
|
143
|
+
expect(Object.keys((await widgetsBy("Bolt"))[0] ?? {})).toEqual([
|
|
144
|
+
"uri",
|
|
145
|
+
"name",
|
|
146
|
+
"maker",
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("answers a calm empty list for an entity that exists and no row names", async () => {
|
|
151
|
+
expect(await widgetsBy("Idle")).toEqual([]);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("refuses a value the noun's lookup cannot resolve, offering what a lookup miss offers", async () => {
|
|
155
|
+
await expect(widgetsBy(["Bolt", "Bolts"])).rejects.toMatchObject({
|
|
156
|
+
code: "INVALID_INPUT",
|
|
157
|
+
message: 'No maker is named "Bolts".',
|
|
158
|
+
suggestions: ["Bolt"],
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("refuses an empty value as empty input", async () => {
|
|
163
|
+
await expect(widgetsBy("")).rejects.toMatchObject({
|
|
164
|
+
code: "INVALID_INPUT",
|
|
165
|
+
message: 'Invalid maker "(empty)".',
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("is a configuration error when no story declares the noun", async () => {
|
|
170
|
+
const orphan = compilePack(
|
|
171
|
+
WIDGET,
|
|
172
|
+
distributionSource("test:links"),
|
|
173
|
+
PREFIXES,
|
|
174
|
+
)[0] as VerbSpec;
|
|
175
|
+
await expect(orphan.run({ maker: "Acme" }, rt)).rejects.toMatchObject({
|
|
176
|
+
code: "CONFIG_ERROR",
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe("a noun filter across the shipped and the project's stories", () => {
|
|
182
|
+
const shipped = (...stories: PackDefinition[]): CapabilityModule[] =>
|
|
183
|
+
stories.map((story) =>
|
|
184
|
+
compileStoryModule(
|
|
185
|
+
story,
|
|
186
|
+
distributionSource("test:shipped"),
|
|
187
|
+
PREFIXES,
|
|
188
|
+
(noun) => STORIES.get(noun)?.lookup,
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
const project = (stories: unknown[]): ConfigLayers =>
|
|
192
|
+
({
|
|
193
|
+
config: { stories, prefixes: PREFIXES },
|
|
194
|
+
origins: { packs: "default", stories: "project" },
|
|
195
|
+
}) as unknown as ConfigLayers;
|
|
196
|
+
const makerFilter = (modules: readonly CapabilityModule[], maker: string) =>
|
|
197
|
+
(
|
|
198
|
+
modules
|
|
199
|
+
.flatMap((module) => module.verbs)
|
|
200
|
+
.find((v) => verbKey(v.path) === "widget list") as VerbSpec
|
|
201
|
+
).run({ maker: [maker] }, rt) as Promise<PackPage>;
|
|
202
|
+
|
|
203
|
+
it("a project story resolves its filter through a shipped noun", async () => {
|
|
204
|
+
const modules = assembleEffectiveModules(shipped(MAKER), project([WIDGET]));
|
|
205
|
+
const page = await makerFilter(modules, "Bolt");
|
|
206
|
+
expect(page.rows.map((row) => row.name)).toEqual(["Slider"]);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("a shipped filter resolves through the project's override of the noun it names", async () => {
|
|
210
|
+
const byCode = {
|
|
211
|
+
noun: "maker",
|
|
212
|
+
lookup: { by: "ex:code", type: "ex:Maker" },
|
|
213
|
+
};
|
|
214
|
+
const modules = assembleEffectiveModules(
|
|
215
|
+
shipped(MAKER, WIDGET),
|
|
216
|
+
project([byCode]),
|
|
217
|
+
);
|
|
218
|
+
const page = await makerFilter(modules, "A1");
|
|
219
|
+
expect(page.rows.map((row) => row.name)).toEqual(["Button"]);
|
|
220
|
+
await expect(makerFilter(modules, "Acme")).rejects.toMatchObject({
|
|
221
|
+
code: "INVALID_INPUT",
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("refuses a story naming a noun no story declares, where it is assembled", () => {
|
|
226
|
+
expect(() => assembleEffectiveModules([], project([WIDGET]))).toThrow(
|
|
227
|
+
/Invalid story in config: "widget" names the noun "maker"/,
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("a project overriding a named noun with no lookup breaks only the filter, when used", async () => {
|
|
232
|
+
const listOnly = { noun: "maker", list: WIDGET.list };
|
|
233
|
+
const modules = assembleEffectiveModules(
|
|
234
|
+
shipped(MAKER, WIDGET),
|
|
235
|
+
project([listOnly]),
|
|
236
|
+
);
|
|
237
|
+
const widgets = modules
|
|
238
|
+
.flatMap((module) => module.verbs)
|
|
239
|
+
.find((v) => verbKey(v.path) === "widget list") as VerbSpec;
|
|
240
|
+
expect(((await widgets.run({}, rt)) as PackPage).rows).toHaveLength(3);
|
|
241
|
+
await expect(makerFilter(modules, "Bolt")).rejects.toMatchObject({
|
|
242
|
+
code: "CONFIG_ERROR",
|
|
243
|
+
message: expect.stringMatching(
|
|
244
|
+
/The "maker" story in config declares no lookup/,
|
|
245
|
+
),
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("a package story is screened against the assembled nouns, whatever the order", () => {
|
|
250
|
+
const entry = { source: "pkg/stories/widget.json", definition: WIDGET };
|
|
251
|
+
const withMaker = screenPackageStories(
|
|
252
|
+
assembleEffectiveModules([], project([MAKER]), [entry]),
|
|
253
|
+
);
|
|
254
|
+
expect(withMaker.modules.map((module) => module.name)).toContain("widget");
|
|
255
|
+
expect(withMaker.problems).toEqual([]);
|
|
256
|
+
|
|
257
|
+
const other = { noun: "gadget", lookup: MAKER.lookup };
|
|
258
|
+
const without = screenPackageStories(
|
|
259
|
+
assembleEffectiveModules([], project([other]), [entry]),
|
|
260
|
+
);
|
|
261
|
+
expect(without.modules.map((module) => module.name)).toEqual(["gadget"]);
|
|
262
|
+
expect(without.problems).toEqual([
|
|
263
|
+
{
|
|
264
|
+
source: "pkg/stories/widget.json",
|
|
265
|
+
message: 'it names the noun "maker", and no story declares it.',
|
|
266
|
+
},
|
|
267
|
+
]);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe("a many expand field", () => {
|
|
272
|
+
it("is one cell per child holding every value, sorted", async () => {
|
|
273
|
+
const output = (await verb(MAKER, "lookup").run(
|
|
274
|
+
{ name: ["ex:acme"] },
|
|
275
|
+
rt,
|
|
276
|
+
)) as LookupOutput;
|
|
277
|
+
const widgets = output.results[0]?.widgets as { aliases?: string }[];
|
|
278
|
+
expect(widgets).toHaveLength(1);
|
|
279
|
+
expect(widgets[0]?.aliases).toBe("Btn btn push-button");
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
describe("a grouped expand", () => {
|
|
284
|
+
it("orders rows that tie on orderBy the same way on every store", async () => {
|
|
285
|
+
const labels: string[] = [];
|
|
286
|
+
for (let boot = 0; boot < 3; boot += 1) {
|
|
287
|
+
const fresh = await buildFixtureRuntime({ ttl: TTL, prefixes: PREFIXES });
|
|
288
|
+
const output = (await verb(MAKER, "lookup").run(
|
|
289
|
+
{ name: ["Bolt"] },
|
|
290
|
+
fresh.rt,
|
|
291
|
+
)) as LookupOutput;
|
|
292
|
+
const parts = output.results[0]?.parts as { label: string }[];
|
|
293
|
+
labels.push(parts.map((part) => part.label).join(""));
|
|
294
|
+
}
|
|
295
|
+
expect(labels).toEqual(["abcdef", "abcdef", "abcdef"]);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
describe("the grammar", () => {
|
|
300
|
+
const withFilter = (filter: Record<string, unknown>): unknown => ({
|
|
301
|
+
...WIDGET,
|
|
302
|
+
list: { ...WIDGET.list, filters: [filter] },
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("accepts both stories as declared", () => {
|
|
306
|
+
expect(() => parsePackDefinition(MAKER, "test")).not.toThrow();
|
|
307
|
+
expect(() => parsePackDefinition(WIDGET, "test")).not.toThrow();
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it.each([
|
|
311
|
+
[
|
|
312
|
+
"a noun filter with no entity",
|
|
313
|
+
{ param: "maker", variable: "maker", noun: "maker" },
|
|
314
|
+
/must declare the "entity"/,
|
|
315
|
+
],
|
|
316
|
+
[
|
|
317
|
+
"a noun filter with a vocabulary of its own",
|
|
318
|
+
{
|
|
319
|
+
param: "maker",
|
|
320
|
+
variable: "maker",
|
|
321
|
+
noun: "maker",
|
|
322
|
+
entity: "makerUri",
|
|
323
|
+
values: ["Acme"],
|
|
324
|
+
},
|
|
325
|
+
/mutually exclusive/,
|
|
326
|
+
],
|
|
327
|
+
[
|
|
328
|
+
"an entity the query does not project",
|
|
329
|
+
{ param: "maker", variable: "maker", noun: "maker", entity: "absent" },
|
|
330
|
+
/"absent" is filtered or searched but not projected/,
|
|
331
|
+
],
|
|
332
|
+
[
|
|
333
|
+
"an entity without a noun",
|
|
334
|
+
{
|
|
335
|
+
param: "maker",
|
|
336
|
+
variable: "maker",
|
|
337
|
+
values: ["Acme"],
|
|
338
|
+
entity: "makerUri",
|
|
339
|
+
},
|
|
340
|
+
/belong to a filter that names a "noun"/,
|
|
341
|
+
],
|
|
342
|
+
])("refuses %s", (_, filter, reason) => {
|
|
343
|
+
expect(() => parsePackDefinition(withFilter(filter), "test")).toThrow(
|
|
344
|
+
reason,
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it.each([
|
|
349
|
+
[
|
|
350
|
+
"many with blankWhenSelf",
|
|
351
|
+
{ many: true, blankWhenSelf: true },
|
|
352
|
+
{},
|
|
353
|
+
/mutually exclusive/,
|
|
354
|
+
],
|
|
355
|
+
[
|
|
356
|
+
"many on the GraphQL lane",
|
|
357
|
+
{ many: true },
|
|
358
|
+
{ source: "graphql" },
|
|
359
|
+
/sets "many", which only the SPARQL lane/,
|
|
360
|
+
],
|
|
361
|
+
[
|
|
362
|
+
"ordering by a many field",
|
|
363
|
+
{ many: true },
|
|
364
|
+
{ orderBy: ["aliases"] },
|
|
365
|
+
/a "many" field/,
|
|
366
|
+
],
|
|
367
|
+
])("refuses %s", (_, field, expand, reason) => {
|
|
368
|
+
const lookup = MAKER.lookup as NonNullable<PackDefinition["lookup"]>;
|
|
369
|
+
const story = {
|
|
370
|
+
...MAKER,
|
|
371
|
+
lookup: {
|
|
372
|
+
...lookup,
|
|
373
|
+
...("source" in expand ? { source: "graphql" } : {}),
|
|
374
|
+
expand: [
|
|
375
|
+
{
|
|
376
|
+
...lookup.expand?.[0],
|
|
377
|
+
...("orderBy" in expand ? expand : {}),
|
|
378
|
+
select: [{ name: "aliases", property: "ex:alias", ...field }],
|
|
379
|
+
},
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
expect(() => parsePackDefinition(story, "test")).toThrow(reason);
|
|
384
|
+
});
|
|
385
|
+
});
|