@canonical/pragma-cli 0.29.0 → 0.31.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 +128 -47
- package/dist/pragma +0 -0
- package/package.json +15 -13
- package/src/completions/constants.ts +7 -0
- package/src/completions/handleQuery.test.ts +32 -0
- package/src/completions/handleQuery.ts +20 -1
- package/src/completions/queryCompletions.test.ts +5 -0
- package/src/completions/queryCompletions.ts +17 -3
- package/src/completions/querySocket.test.ts +31 -0
- package/src/completions/querySocket.ts +36 -9
- package/src/config/defaultConfig.test.ts +33 -0
- package/src/config/defaultConfig.ts +59 -0
- package/src/config/defaults.json +17 -0
- package/src/config/findProjectConfigPath.test.ts +53 -0
- package/src/config/findProjectConfigPath.ts +36 -0
- package/src/config/index.ts +17 -2
- package/src/config/mergeConfigFileUpdate.ts +58 -0
- package/src/config/parseConfigValues.ts +217 -0
- package/src/config/readConfig.test.ts +104 -13
- package/src/config/readConfig.ts +12 -153
- package/src/config/readConfigLayers.test.ts +109 -0
- package/src/config/readConfigLayers.ts +118 -0
- package/src/config/resolveGlobalConfigPath.ts +13 -0
- package/src/config/resolveWriteConfigPath.test.ts +53 -0
- package/src/config/resolveWriteConfigPath.ts +31 -0
- package/src/config/types.ts +83 -1
- package/src/config/writeConfig.ts +25 -55
- package/src/constants.ts +3 -1
- package/src/domains/block/commands/list.ts +5 -90
- package/src/domains/block/commands/lookup.ts +8 -167
- package/src/domains/block/commands/sample.ts +2 -1
- package/src/domains/block/formatters/list.test.ts +3 -3
- package/src/domains/block/formatters/lookup.test.ts +5 -5
- package/src/domains/block/mcp/specs.ts +16 -196
- package/src/domains/block/orchestration/enrichBlocks.ts +6 -3
- package/src/domains/block/orchestration/resolveBlockLookup.ts +2 -1
- package/src/domains/block/stories.test.ts +28 -0
- package/src/domains/block/stories.ts +260 -0
- package/src/domains/config/commands/channel.test.ts +30 -3
- package/src/domains/config/commands/channel.ts +25 -8
- package/src/domains/config/commands/configScope.ts +46 -0
- package/src/domains/config/commands/framework.test.ts +32 -1
- package/src/domains/config/commands/framework.ts +26 -8
- package/src/domains/config/commands/show.ts +5 -45
- package/src/domains/config/commands/tier.test.ts +20 -2
- package/src/domains/config/commands/tier.ts +25 -8
- package/src/domains/config/commands/trace.test.ts +19 -2
- package/src/domains/config/commands/trace.ts +6 -3
- package/src/domains/config/formatters/channel.test.ts +20 -6
- package/src/domains/config/formatters/channel.ts +14 -11
- package/src/domains/config/formatters/framework.ts +14 -11
- package/src/domains/config/formatters/show.test.ts +27 -0
- package/src/domains/config/formatters/show.ts +27 -4
- package/src/domains/config/formatters/tier.test.ts +26 -10
- package/src/domains/config/formatters/tier.ts +19 -11
- package/src/domains/config/formatters/trace.ts +7 -7
- package/src/domains/config/mcp/specs.ts +33 -53
- package/src/domains/config/operations/show.test.ts +18 -0
- package/src/domains/config/operations/show.ts +7 -1
- package/src/domains/config/operations/types.ts +7 -0
- package/src/domains/config/operations/validateTier.test.ts +9 -0
- package/src/domains/config/operations/validateTier.ts +10 -2
- package/src/domains/config/stories.ts +42 -0
- package/src/domains/config/tasks/index.ts +1 -0
- package/src/domains/config/tasks/setChannel.ts +13 -28
- package/src/domains/config/tasks/setFramework.ts +11 -30
- package/src/domains/config/tasks/setTier.ts +10 -29
- package/src/domains/config/tasks/setTrace.ts +10 -28
- package/src/domains/config/tasks/writeConfigField.ts +41 -0
- package/src/domains/create/generatorPack/bundled.ts +49 -0
- package/src/domains/create/generatorPack/compileGeneratorPack.test.ts +159 -0
- package/src/domains/create/generatorPack/compileGeneratorPack.ts +312 -0
- package/src/domains/create/index.ts +13 -7
- package/src/domains/create/mcp/specs.ts +6 -161
- package/src/domains/create/renderGeneratorUi.test.ts +103 -0
- package/src/domains/create/renderGeneratorUi.ts +65 -0
- package/src/domains/doctor/formatters/doctor.test.ts +50 -2
- package/src/domains/doctor/formatters/doctor.ts +90 -38
- package/src/domains/doctor/operations/checks/checkConfigFile.ts +19 -5
- package/src/domains/doctor/operations/checks/checkMcpCommands.ts +133 -0
- package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +1 -1
- package/src/domains/doctor/operations/checks/checkPackageRefs.ts +32 -26
- package/src/domains/doctor/operations/checks/checkSkillsSymlinked.ts +1 -1
- package/src/domains/doctor/operations/checks/index.ts +1 -0
- package/src/domains/doctor/operations/checks.test.ts +160 -7
- package/src/domains/doctor/operations/runChecks.test.ts +15 -6
- package/src/domains/doctor/operations/runChecks.ts +2 -0
- package/src/domains/doctor/operations/types.ts +23 -1
- package/src/domains/graph/commands/inspect.test.ts +2 -2
- package/src/domains/graph/commands/query.test.ts +5 -3
- package/src/domains/graph/formatters/inspect.ts +7 -7
- package/src/domains/graph/formatters/query.test.ts +87 -0
- package/src/domains/graph/formatters/query.ts +42 -5
- package/src/domains/graph/helpers/resolveUri.test.ts +50 -0
- package/src/domains/graph/helpers/resolveUri.ts +28 -21
- package/src/domains/graph/operations/inspectUri.test.ts +5 -5
- package/src/domains/graphql/commands/build.test.ts +5 -3
- package/src/domains/graphql/commands/build.ts +8 -16
- package/src/domains/graphql/commands/check.test.ts +5 -3
- package/src/domains/graphql/commands/check.ts +7 -13
- package/src/domains/graphql/commands/index.ts +1 -0
- package/src/domains/graphql/commands/serve.test.ts +46 -0
- package/src/domains/graphql/commands/serve.ts +141 -0
- package/src/domains/graphql/constants.ts +10 -0
- package/src/domains/graphql/helpers/gatherSources.test.ts +92 -0
- package/src/domains/graphql/helpers/gatherSources.ts +58 -0
- package/src/domains/graphql/helpers/index.ts +2 -0
- package/src/domains/graphql/helpers/parsePrefixes.test.ts +3 -3
- package/src/domains/graphql/helpers/parsePrefixes.ts +3 -3
- package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +9 -0
- package/src/domains/graphql/helpers/resolveSourceFiles.ts +24 -3
- package/src/domains/graphql/helpers/routeGraphql.test.ts +43 -0
- package/src/domains/graphql/helpers/routeGraphql.ts +28 -0
- package/src/domains/graphql/index.ts +9 -6
- package/src/domains/graphql/operations/compileSchema.test.ts +23 -47
- package/src/domains/graphql/operations/compileSchema.ts +23 -25
- package/src/domains/graphql/operations/createSchemaServer.test.ts +50 -0
- package/src/domains/graphql/operations/createSchemaServer.ts +75 -0
- package/src/domains/graphql/operations/ensureSchemaArtifact.test.ts +167 -0
- package/src/domains/graphql/operations/ensureSchemaArtifact.ts +178 -0
- package/src/domains/graphql/operations/index.ts +10 -0
- package/src/domains/info/formatters/upgrade.test.ts +7 -4
- package/src/domains/info/formatters/upgrade.ts +3 -1
- package/src/domains/info/operations/collectEntityCounts.test.ts +156 -0
- package/src/domains/info/operations/collectEntityCounts.ts +123 -0
- package/src/domains/info/operations/collectInfo.test.ts +14 -3
- package/src/domains/info/operations/collectInfo.ts +12 -15
- package/src/domains/info/operations/index.ts +1 -0
- package/src/domains/info/types.ts +13 -0
- package/src/domains/llm/capabilities.test.ts +24 -4
- package/src/domains/llm/commands/capabilities.ts +12 -3
- package/src/domains/llm/commands/llm.ts +5 -1
- package/src/domains/llm/data/commandReference.ts +20 -11
- package/src/domains/llm/data/decisionTrees.ts +10 -5
- package/src/domains/llm/data/toolCatalog.ts +55 -18
- package/src/domains/llm/formatters/orientation.ts +5 -1
- package/src/domains/llm/llmCommand.test.ts +11 -3
- package/src/domains/llm/mcp/specs.ts +3 -4
- package/src/domains/llm/operations/collectContext.test.ts +64 -0
- package/src/domains/llm/operations/collectContext.ts +7 -17
- package/src/domains/modifier/commands/list.ts +5 -38
- package/src/domains/modifier/commands/lookup.ts +8 -79
- package/src/domains/modifier/commands/sample.ts +2 -1
- package/src/domains/modifier/mcp/specs.ts +15 -94
- package/src/domains/modifier/operations/lookup.ts +5 -3
- package/src/domains/modifier/orchestration/resolveModifierLookup.ts +2 -1
- package/src/domains/modifier/stories.test.ts +20 -0
- package/src/domains/modifier/stories.ts +86 -0
- package/src/domains/ontology/commands/list.test.ts +5 -3
- package/src/domains/ontology/commands/list.ts +5 -58
- package/src/domains/ontology/commands/show.test.ts +85 -9
- package/src/domains/ontology/commands/show.ts +6 -58
- package/src/domains/ontology/formatters/index.ts +1 -0
- package/src/domains/ontology/formatters/list.ts +37 -12
- package/src/domains/ontology/formatters/show.ts +361 -64
- package/src/domains/ontology/helpers/buildClassTree.ts +89 -0
- package/src/domains/ontology/helpers/completeClassNames.ts +43 -0
- package/src/domains/ontology/helpers/expandOntologyIris.ts +79 -0
- package/src/domains/ontology/helpers/index.ts +14 -0
- package/src/domains/ontology/helpers/queryClasses.ts +32 -16
- package/src/domains/ontology/helpers/queryProperties.ts +39 -6
- package/src/domains/ontology/helpers/queryTboxFacts.ts +160 -0
- package/src/domains/ontology/mcp/specs.ts +7 -84
- package/src/domains/ontology/operations/listOntologies.test.ts +80 -3
- package/src/domains/ontology/operations/listOntologies.ts +126 -30
- package/src/domains/ontology/operations/showOntology.test.ts +131 -12
- package/src/domains/ontology/operations/showOntology.ts +289 -7
- package/src/domains/ontology/operations/showOntologyRaw.test.ts +4 -2
- package/src/domains/ontology/stories.test.ts +36 -0
- package/src/domains/ontology/stories.ts +153 -0
- package/src/domains/refs/operations/updateRefs.ts +2 -38
- package/src/domains/setup/commands/index.ts +1 -0
- package/src/domains/setup/commands/setup.ts +70 -0
- package/src/domains/setup/commands/skills.test.ts +6 -2
- package/src/domains/setup/commands/skills.ts +6 -2
- package/src/domains/setup/helpers/runSetupTask.test.ts +148 -150
- package/src/domains/setup/helpers/runSetupTask.ts +62 -70
- package/src/domains/setup/index.ts +7 -3
- package/src/domains/setup/operations/setupLsp.test.ts +3 -2
- package/src/domains/setup/operations/setupLsp.ts +7 -2
- package/src/domains/setup/operations/setupMcp.test.ts +6 -1
- package/src/domains/shared/bootStore.bareCore.test.ts +63 -0
- package/src/domains/shared/bootStore.test.ts +82 -0
- package/src/domains/shared/bootStore.ts +57 -18
- package/src/domains/shared/compactUri.test.ts +11 -0
- package/src/domains/shared/compactUri.ts +10 -5
- package/src/domains/shared/context.ts +2 -2
- package/src/domains/shared/contracts.ts +11 -0
- package/src/domains/shared/createInteractivePromptSession.test.ts +439 -0
- package/src/domains/shared/createInteractivePromptSession.ts +236 -0
- package/src/domains/shared/emptyErrorRecovery.test.ts +23 -26
- package/src/domains/shared/extractLocalName.test.ts +3 -3
- package/src/domains/shared/formatters.ts +23 -2
- package/src/domains/shared/listTiers.ts +40 -0
- package/src/domains/shared/loaders/bundledLoader.test.ts +248 -0
- package/src/domains/shared/loaders/bundledLoader.ts +158 -12
- package/src/domains/shared/loaders/gitLoader.ts +1 -2
- package/src/domains/shared/loaders/index.ts +4 -1
- package/src/domains/shared/loaders/localLoader.ts +2 -4
- package/src/domains/shared/loaders/readPackageDir.test.ts +58 -0
- package/src/domains/shared/loaders/readPackageDir.ts +82 -9
- package/src/domains/shared/loaders/storyAssetsPlugin.test.ts +84 -0
- package/src/domains/shared/loaders/storyAssetsPlugin.ts +46 -0
- package/src/domains/shared/lookupMany.test.ts +135 -0
- package/src/domains/shared/lookupMany.ts +50 -2
- package/src/domains/shared/mergeAndParseRefs.test.ts +89 -0
- package/src/domains/shared/mergeAndParseRefs.ts +44 -0
- package/src/domains/shared/namespaces.ts +13 -5
- package/src/domains/shared/packages.ts +10 -17
- package/src/domains/shared/parseSampleCount.test.ts +47 -0
- package/src/domains/shared/parseSampleCount.ts +45 -0
- package/src/domains/shared/prefixes.test.ts +211 -0
- package/src/domains/shared/prefixes.ts +182 -15
- package/src/domains/shared/renderers.ts +5 -5
- package/src/domains/shared/resolveConfiguredGraphs.test.ts +27 -0
- package/src/domains/shared/resolveConfiguredGraphs.ts +41 -0
- package/src/domains/shared/resolveLookupExitCode.test.ts +48 -0
- package/src/domains/shared/resolveLookupExitCode.ts +42 -0
- package/src/domains/shared/runtime.ts +4 -63
- package/src/domains/shared/semanticPackage.test.ts +89 -0
- package/src/domains/shared/semanticPackage.ts +34 -3
- package/src/domains/shared/stories/compileLookupCommand.test.ts +145 -0
- package/src/domains/shared/stories/compileLookupCommand.ts +102 -0
- package/src/domains/shared/stories/compileLookupTool.test.ts +105 -0
- package/src/domains/shared/stories/compileLookupTool.ts +96 -0
- package/src/domains/shared/stories/compileReadCommand.test.ts +121 -0
- package/src/domains/shared/stories/compileReadCommand.ts +48 -0
- package/src/domains/shared/stories/compileReadTool.test.ts +64 -0
- package/src/domains/shared/stories/compileReadTool.ts +38 -0
- package/src/domains/shared/stories/condense.test.ts +18 -0
- package/src/domains/shared/stories/condense.ts +15 -0
- package/src/domains/shared/stories/index.ts +20 -0
- package/src/domains/shared/stories/normalizeNames.test.ts +20 -0
- package/src/domains/shared/stories/normalizeNames.ts +22 -0
- package/src/domains/shared/stories/pack/applyPackFilters.test.ts +151 -0
- package/src/domains/shared/stories/pack/applyPackFilters.ts +111 -0
- package/src/domains/shared/stories/pack/applyPackSearch.test.ts +57 -0
- package/src/domains/shared/stories/pack/applyPackSearch.ts +41 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +81 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.ts +154 -0
- package/src/domains/shared/stories/pack/bundled/index.ts +23 -0
- package/src/domains/shared/stories/pack/bundled/standardPack.ts +164 -0
- package/src/domains/shared/stories/pack/bundled/tierPack.ts +50 -0
- package/src/domains/shared/stories/pack/collectPackStories.test.ts +406 -0
- package/src/domains/shared/stories/pack/collectPackStories.ts +158 -0
- package/src/domains/shared/stories/pack/compilePackCommands.ts +50 -0
- package/src/domains/shared/stories/pack/compilePackStories.test.ts +751 -0
- package/src/domains/shared/stories/pack/compilePackStories.ts +724 -0
- package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +55 -0
- package/src/domains/shared/stories/pack/index.ts +42 -0
- package/src/domains/shared/stories/pack/reservedVerbs.test.ts +213 -0
- package/src/domains/shared/stories/pack/reservedVerbs.ts +170 -0
- package/src/domains/shared/stories/pack/runSelectQuery.ts +31 -0
- package/src/domains/shared/stories/pack/standardParity.test.ts +381 -0
- package/src/domains/shared/stories/pack/types.ts +224 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +742 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +859 -0
- package/src/domains/shared/stories/projectCliParameters.test.ts +59 -0
- package/src/domains/shared/stories/projectCliParameters.ts +57 -0
- package/src/domains/shared/stories/projectToolParams.test.ts +50 -0
- package/src/domains/shared/stories/projectToolParams.ts +32 -0
- package/src/domains/shared/stories/requirePragmaContext.test.ts +23 -0
- package/src/domains/shared/stories/requirePragmaContext.ts +23 -0
- package/src/domains/shared/stories/resolveLookupDetailed.test.ts +57 -0
- package/src/domains/shared/stories/resolveLookupDetailed.ts +27 -0
- package/src/domains/shared/stories/types.ts +179 -0
- package/src/domains/shared/suggestions/expandGlob.ts +1 -0
- package/src/domains/shared/suggestions/suggestNames.ts +43 -10
- package/src/domains/shared/types/index.ts +5 -9
- package/src/domains/shared/types/ontology.ts +119 -24
- package/src/domains/shared/types/standard.ts +9 -52
- package/src/domains/skill/commands/index.ts +3 -1
- package/src/domains/skill/commands/list.test.ts +6 -2
- package/src/domains/skill/commands/list.ts +5 -63
- package/src/domains/skill/commands/lookup.test.ts +118 -0
- package/src/domains/skill/commands/lookup.ts +14 -0
- package/src/domains/skill/formatters/index.ts +1 -0
- package/src/domains/skill/formatters/lookup.test.ts +46 -0
- package/src/domains/skill/formatters/lookup.ts +57 -0
- package/src/domains/skill/helpers/resolveSkillSources.ts +0 -1
- package/src/domains/skill/index.ts +7 -3
- package/src/domains/skill/mcp/specs.ts +10 -29
- package/src/domains/skill/operations/discover.test.ts +61 -30
- package/src/domains/skill/operations/discover.ts +28 -37
- package/src/domains/skill/operations/index.ts +2 -1
- package/src/domains/skill/operations/list.test.ts +15 -7
- package/src/domains/skill/operations/lookup.test.ts +91 -0
- package/src/domains/skill/operations/lookup.ts +70 -0
- package/src/domains/skill/stories.test.ts +43 -0
- package/src/domains/skill/stories.ts +103 -0
- package/src/domains/skill/types.ts +8 -0
- package/src/domains/token/commands/lookup.test.ts +8 -0
- package/src/domains/token/commands/lookup.ts +12 -0
- package/src/domains/token/commands/sample.ts +2 -1
- package/src/domains/token/featureFlag.ts +17 -0
- package/src/domains/token/index.ts +5 -0
- package/src/domains/token/mcp/specs.ts +18 -2
- package/src/domains/token/orchestration/resolveTokenLookup.ts +2 -1
- package/src/domains/trace/commands/resolveTraceLimit.test.ts +31 -0
- package/src/domains/trace/commands/show.ts +30 -4
- package/src/domains/trace/tracePlugin.test.ts +1 -1
- package/src/index.ts +1 -13
- package/src/mcp/registerResources.test.ts +382 -74
- package/src/mcp/registerResources.ts +5 -348
- package/src/mcp/resources/buildGraphIndex.ts +167 -0
- package/src/mcp/resources/buildResourceList.test.ts +97 -0
- package/src/mcp/resources/buildResourceList.ts +176 -0
- package/src/mcp/resources/classifyEntity.test.ts +40 -0
- package/src/mcp/resources/classifyEntity.ts +27 -0
- package/src/mcp/resources/constants.ts +105 -0
- package/src/mcp/resources/displayPredicates.ts +62 -0
- package/src/mcp/resources/pickFirstValue.test.ts +29 -0
- package/src/mcp/resources/pickFirstValue.ts +26 -0
- package/src/mcp/resources/pickPrimaryType.test.ts +41 -0
- package/src/mcp/resources/pickPrimaryType.ts +26 -0
- package/src/mcp/resources/rankUriCompletions.test.ts +52 -0
- package/src/mcp/resources/rankUriCompletions.ts +64 -0
- package/src/mcp/resources/readEntity.ts +169 -0
- package/src/mcp/resources/registerResources.ts +126 -0
- package/src/mcp/resources/types.ts +128 -0
- package/src/mcp/tools/index.ts +22 -5
- package/src/mcp/tools/registerTools.test.ts +167 -34
- package/src/mcp/types.ts +4 -0
- package/src/pipeline/collectCommands.test.ts +151 -1
- package/src/pipeline/collectCommands.ts +35 -13
- package/src/pipeline/createProgram.test.ts +5 -1
- package/src/pipeline/createProgram.ts +2 -2
- package/src/pipeline/firstRun.test.ts +80 -0
- package/src/pipeline/firstRun.ts +99 -0
- package/src/pipeline/parseGlobalFlags.test.ts +102 -1
- package/src/pipeline/parseGlobalFlags.ts +98 -9
- package/src/pipeline/resolveCommandKind.test.ts +12 -0
- package/src/pipeline/resolveCommandKind.ts +4 -0
- package/src/pipeline/rootHelp.test.ts +87 -0
- package/src/pipeline/rootHelp.ts +265 -0
- package/src/pipeline/runCli.orchestration.test.ts +28 -12
- package/src/pipeline/runCli.test.ts +17 -4
- package/src/pipeline/runCli.ts +202 -25
- package/src/testing/cli.ts +30 -2
- package/src/testing/createTestMcpClient.ts +4 -1
- package/src/testing/dsFixtures.ts +21 -4
- package/src/testing/index.ts +7 -0
- package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +1207 -0
- package/src/testing/integration/cli-user-stories.test.ts +63 -0
- package/src/testing/integration/cross-binary-byte-equality.test.ts +129 -0
- package/src/testing/integration/edge-cases.test.ts +62 -50
- package/src/testing/integration/executor-execution.test.ts +103 -0
- package/src/testing/integration/executor-golden.test.ts +145 -0
- package/src/testing/integration/mcp-surface.test.ts +40 -15
- package/src/testing/integration/parity.test.ts +136 -82
- package/src/testing/regression/0001-skill-discovery-granularity.test.ts +71 -0
- package/src/testing/setupXdgIsolation.ts +26 -0
- package/src/testing/standardParityFixtures.ts +35 -0
- package/src/testing/store.ts +4 -4
- package/src/testing/storyFixtures.ts +63 -0
- package/src/domains/create/commands/component.test.ts +0 -166
- package/src/domains/create/commands/component.ts +0 -123
- package/src/domains/create/commands/index.ts +0 -3
- package/src/domains/create/commands/package.test.ts +0 -35
- package/src/domains/create/commands/package.ts +0 -21
- package/src/domains/create/generators.ts +0 -8
- package/src/domains/standard/commands/categories.test.ts +0 -70
- package/src/domains/standard/commands/categories.ts +0 -48
- package/src/domains/standard/commands/index.ts +0 -6
- package/src/domains/standard/commands/list.test.ts +0 -105
- package/src/domains/standard/commands/list.ts +0 -90
- package/src/domains/standard/commands/lookup.test.ts +0 -135
- package/src/domains/standard/commands/lookup.ts +0 -99
- package/src/domains/standard/commands/sample.ts +0 -57
- package/src/domains/standard/formatters/categories.test.ts +0 -44
- package/src/domains/standard/formatters/categories.ts +0 -38
- package/src/domains/standard/formatters/index.ts +0 -10
- package/src/domains/standard/formatters/list.test.ts +0 -169
- package/src/domains/standard/formatters/list.ts +0 -184
- package/src/domains/standard/formatters/lookup.test.ts +0 -95
- package/src/domains/standard/formatters/lookup.ts +0 -101
- package/src/domains/standard/formatters/sample.ts +0 -15
- package/src/domains/standard/formatters/types.ts +0 -31
- package/src/domains/standard/index.ts +0 -40
- package/src/domains/standard/mcp/index.ts +0 -2
- package/src/domains/standard/mcp/specs.ts +0 -244
- package/src/domains/standard/operations/categories.test.ts +0 -61
- package/src/domains/standard/operations/categories.ts +0 -38
- package/src/domains/standard/operations/index.ts +0 -6
- package/src/domains/standard/operations/list.test.ts +0 -75
- package/src/domains/standard/operations/list.ts +0 -64
- package/src/domains/standard/operations/lookup.test.ts +0 -58
- package/src/domains/standard/operations/lookup.ts +0 -151
- package/src/domains/standard/operations/sample.ts +0 -35
- package/src/domains/standard/orchestration/buildStandardFilters.ts +0 -11
- package/src/domains/standard/orchestration/index.ts +0 -4
- package/src/domains/standard/orchestration/resolveStandardList.ts +0 -45
- package/src/domains/standard/orchestration/resolveStandardLookup.ts +0 -32
- package/src/domains/standard/orchestration/standardEmptyError.test.ts +0 -33
- package/src/domains/standard/orchestration/standardEmptyError.ts +0 -29
- package/src/domains/standard/standardConfig.ts +0 -42
- package/src/domains/standard/types.ts +0 -15
- package/src/domains/tier/commands/index.ts +0 -3
- package/src/domains/tier/commands/list.test.ts +0 -67
- package/src/domains/tier/commands/list.ts +0 -59
- package/src/domains/tier/formatters/index.ts +0 -3
- package/src/domains/tier/formatters/list.test.ts +0 -33
- package/src/domains/tier/formatters/list.ts +0 -45
- package/src/domains/tier/index.ts +0 -17
- package/src/domains/tier/mcp/index.ts +0 -2
- package/src/domains/tier/mcp/specs.ts +0 -38
- package/src/domains/tier/operations/index.ts +0 -3
- package/src/domains/tier/operations/list.test.ts +0 -32
- package/src/domains/tier/operations/list.ts +0 -33
- package/src/pipeline/runInteractiveCommand.ts +0 -198
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CommandDefinition,
|
|
3
|
+
type CommandResult,
|
|
4
|
+
createOutputResult,
|
|
5
|
+
} from "@canonical/cli-core";
|
|
6
|
+
import { PragmaError } from "#error";
|
|
7
|
+
import { DEFAULT_PORT } from "../constants.js";
|
|
8
|
+
import { gatherSources, parsePrefixes } from "../helpers/index.js";
|
|
9
|
+
import routeGraphql from "../helpers/routeGraphql.js";
|
|
10
|
+
import createSchemaServer, {
|
|
11
|
+
type SchemaServer,
|
|
12
|
+
} from "../operations/createSchemaServer.js";
|
|
13
|
+
|
|
14
|
+
/** Narrow an unknown param to a string array. */
|
|
15
|
+
function readStringArray(value: unknown): string[] {
|
|
16
|
+
return Array.isArray(value)
|
|
17
|
+
? value.filter((item): item is string => typeof item === "string")
|
|
18
|
+
: [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parse the `--port` flag. A missing flag uses the default; a provided value
|
|
23
|
+
* must be a valid port (1–65535), otherwise it is rejected rather than
|
|
24
|
+
* silently falling back and masking the user's mistake.
|
|
25
|
+
*
|
|
26
|
+
* @throws PragmaError INVALID_INPUT when a provided `--port` is not a valid port.
|
|
27
|
+
*/
|
|
28
|
+
export function readPort(value: unknown): number {
|
|
29
|
+
if (value === undefined || value === null || value === "") {
|
|
30
|
+
return DEFAULT_PORT;
|
|
31
|
+
}
|
|
32
|
+
const text = String(value).trim();
|
|
33
|
+
const port = Number(text);
|
|
34
|
+
if (!/^\d+$/.test(text) || port < 1 || port > 65535) {
|
|
35
|
+
throw PragmaError.invalidInput("port", String(value), {
|
|
36
|
+
recovery: { message: "Provide a port between 1 and 65535." },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return port;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Listen on `port` and block until the process is interrupted, then stop
|
|
44
|
+
* the server and dispose the store.
|
|
45
|
+
*
|
|
46
|
+
* @note Impure — opens a network listener and registers signal handlers.
|
|
47
|
+
*/
|
|
48
|
+
/* v8 ignore start -- the live Bun.serve listener and signal loop run under `pragma graphql serve`, not unit tests */
|
|
49
|
+
async function listen(server: SchemaServer, port: number): Promise<void> {
|
|
50
|
+
const httpServer = Bun.serve({
|
|
51
|
+
port,
|
|
52
|
+
fetch: (request) => routeGraphql(request, server.handler, port),
|
|
53
|
+
});
|
|
54
|
+
await new Promise<void>((resolve) => {
|
|
55
|
+
const shutdown = (): void => {
|
|
56
|
+
httpServer.stop();
|
|
57
|
+
server.dispose();
|
|
58
|
+
resolve();
|
|
59
|
+
};
|
|
60
|
+
process.once("SIGINT", shutdown);
|
|
61
|
+
process.once("SIGTERM", shutdown);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/* v8 ignore stop */
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Builds the `pragma graphql serve` command definition.
|
|
68
|
+
*
|
|
69
|
+
* Compiles the configured ontologies (or explicit TTL sources) and serves
|
|
70
|
+
* a local GraphQL + GraphiQL endpoint until interrupted. With no positional
|
|
71
|
+
* sources it serves every TTL across the semantic packages in
|
|
72
|
+
* `pragma.config.json`.
|
|
73
|
+
*/
|
|
74
|
+
const serveCommand: CommandDefinition = {
|
|
75
|
+
path: ["graphql", "serve"],
|
|
76
|
+
description:
|
|
77
|
+
"Serve a local GraphQL + GraphiQL endpoint over the configured ontologies",
|
|
78
|
+
parameters: [
|
|
79
|
+
{
|
|
80
|
+
name: "sources",
|
|
81
|
+
description:
|
|
82
|
+
"TTL files or globs to serve (default: the configured semantic packages)",
|
|
83
|
+
type: "multiselect",
|
|
84
|
+
positional: true,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "port",
|
|
88
|
+
description: `Port to listen on (default ${DEFAULT_PORT})`,
|
|
89
|
+
type: "string",
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: "prefix",
|
|
93
|
+
description: "Ontology prefix as name=namespace (repeatable)",
|
|
94
|
+
type: "multiselect",
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
meta: {
|
|
98
|
+
examples: [
|
|
99
|
+
"pragma graphql serve",
|
|
100
|
+
"pragma graphql serve ontology.ttl --port 4001",
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
async execute(params, ctx): Promise<CommandResult> {
|
|
104
|
+
if (typeof Bun === "undefined") {
|
|
105
|
+
throw PragmaError.storeError(
|
|
106
|
+
"`pragma graphql serve` requires the Bun runtime.",
|
|
107
|
+
{
|
|
108
|
+
recovery: {
|
|
109
|
+
message: "Run the compiled `pragma` binary or use `bun run`.",
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const sources = await gatherSources(
|
|
116
|
+
readStringArray(params.sources),
|
|
117
|
+
ctx.cwd,
|
|
118
|
+
);
|
|
119
|
+
const prefixes = parsePrefixes(readStringArray(params.prefix));
|
|
120
|
+
const port = readPort(params.port);
|
|
121
|
+
|
|
122
|
+
const server = await createSchemaServer({ sources, prefixes });
|
|
123
|
+
const errorCount = server.diagnostics.filter(
|
|
124
|
+
(d) => d.severity === "error",
|
|
125
|
+
).length;
|
|
126
|
+
process.stdout.write(
|
|
127
|
+
`[ke-graphql] schema compiled — ${server.diagnostics.length} diagnostic(s)${
|
|
128
|
+
errorCount > 0 ? `, ${errorCount} error(s)` : ""
|
|
129
|
+
}\n[ke-graphql] GraphiQL on http://localhost:${port}/graphql (Ctrl-C to stop)\n`,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
await listen(server, port);
|
|
133
|
+
|
|
134
|
+
return createOutputResult(
|
|
135
|
+
{ port, diagnostics: server.diagnostics },
|
|
136
|
+
{ plain: () => `Stopped the graphql server on port ${port}.` },
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export default serveCommand;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Default port `pragma graphql serve` listens on. */
|
|
2
|
+
const DEFAULT_PORT = 4000;
|
|
3
|
+
|
|
4
|
+
/** Default output path for the SDL written by `pragma graphql build`. */
|
|
5
|
+
const DEFAULT_SDL_PATH = "./schema.graphql";
|
|
6
|
+
|
|
7
|
+
/** Default output path for the extraction artifact written by `pragma graphql build`. */
|
|
8
|
+
const DEFAULT_EXTRACTION_PATH = "./extraction.json";
|
|
9
|
+
|
|
10
|
+
export { DEFAULT_EXTRACTION_PATH, DEFAULT_PORT, DEFAULT_SDL_PATH };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { GRAPHQL_CLEAN_TTL } from "#testing";
|
|
6
|
+
import resolveConfiguredGraphs from "../../shared/resolveConfiguredGraphs.js";
|
|
7
|
+
import gatherSources from "./gatherSources.js";
|
|
8
|
+
|
|
9
|
+
vi.mock("../../shared/resolveConfiguredGraphs.js", () => ({
|
|
10
|
+
default: vi.fn(),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const mockResolve = vi.mocked(resolveConfiguredGraphs);
|
|
14
|
+
|
|
15
|
+
describe("gatherSources", () => {
|
|
16
|
+
let dir: string;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
dir = mkdtempSync(join(tmpdir(), "pragma-gather-"));
|
|
20
|
+
writeFileSync(join(dir, "a.ttl"), GRAPHQL_CLEAN_TTL);
|
|
21
|
+
writeFileSync(join(dir, "b.ttl"), GRAPHQL_CLEAN_TTL);
|
|
22
|
+
mockResolve.mockReset();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
rmSync(dir, { recursive: true, force: true });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("reads explicit files into inline sources, ignoring the config", async () => {
|
|
30
|
+
const sources = await gatherSources(["a.ttl"], dir);
|
|
31
|
+
|
|
32
|
+
expect(sources).toEqual([
|
|
33
|
+
{
|
|
34
|
+
content: GRAPHQL_CLEAN_TTL,
|
|
35
|
+
format: "turtle",
|
|
36
|
+
path: join(dir, "a.ttl"),
|
|
37
|
+
},
|
|
38
|
+
]);
|
|
39
|
+
expect(mockResolve).not.toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("expands glob patterns", async () => {
|
|
43
|
+
const sources = await gatherSources(["*.ttl"], dir);
|
|
44
|
+
|
|
45
|
+
expect(sources.map((source) => source.path).sort()).toEqual([
|
|
46
|
+
join(dir, "a.ttl"),
|
|
47
|
+
join(dir, "b.ttl"),
|
|
48
|
+
]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("throws when explicit sources match nothing", async () => {
|
|
52
|
+
await expect(gatherSources(["none-*.ttl"], dir)).rejects.toMatchObject({
|
|
53
|
+
code: "INVALID_INPUT",
|
|
54
|
+
recovery: {
|
|
55
|
+
message: "No files matched the given paths or glob patterns.",
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("falls back to the configured package graphs when no sources are given", async () => {
|
|
61
|
+
mockResolve.mockResolvedValue([
|
|
62
|
+
{
|
|
63
|
+
path: "definitions/ontology.ttl",
|
|
64
|
+
content: GRAPHQL_CLEAN_TTL,
|
|
65
|
+
format: "turtle",
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const sources = await gatherSources([], dir);
|
|
70
|
+
|
|
71
|
+
expect(mockResolve).toHaveBeenCalledWith(dir);
|
|
72
|
+
expect(sources).toEqual([
|
|
73
|
+
{
|
|
74
|
+
content: GRAPHQL_CLEAN_TTL,
|
|
75
|
+
format: "turtle",
|
|
76
|
+
path: "definitions/ontology.ttl",
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("throws when no sources are given and no packages resolve", async () => {
|
|
82
|
+
mockResolve.mockResolvedValue([]);
|
|
83
|
+
|
|
84
|
+
await expect(gatherSources([], dir)).rejects.toMatchObject({
|
|
85
|
+
code: "INVALID_INPUT",
|
|
86
|
+
recovery: {
|
|
87
|
+
message:
|
|
88
|
+
"No TTL sources given and no semantic packages resolved. Pass TTL files or globs, or configure `packages` in pragma.config.json and install them.",
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the TTL sources for a graphql command.
|
|
3
|
+
*
|
|
4
|
+
* When positional paths or globs are given they win; otherwise the sources
|
|
5
|
+
* are the union of every configured semantic package's graphs (the
|
|
6
|
+
* `pragma.config.json` packages, falling back to the defaults). Either way
|
|
7
|
+
* the result is a list of ke `InlineSource`s (content + provenance path),
|
|
8
|
+
* so the compiler and the dev server load the exact same bytes.
|
|
9
|
+
*
|
|
10
|
+
* @note Impure — reads files and resolves packages from disk.
|
|
11
|
+
*
|
|
12
|
+
* @param positional - Explicit TTL file paths or glob patterns (may be empty).
|
|
13
|
+
* @param cwd - Working directory for file and config resolution.
|
|
14
|
+
* @returns In-memory TTL sources to compile or serve.
|
|
15
|
+
* @throws PragmaError (INVALID_INPUT) when nothing resolves.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { readFileSync } from "node:fs";
|
|
19
|
+
import type { InlineSource } from "@canonical/ke";
|
|
20
|
+
import { PragmaError } from "#error";
|
|
21
|
+
import resolveConfiguredGraphs from "../../shared/resolveConfiguredGraphs.js";
|
|
22
|
+
import resolveSourceFiles from "./resolveSourceFiles.js";
|
|
23
|
+
|
|
24
|
+
export default async function gatherSources(
|
|
25
|
+
positional: readonly string[],
|
|
26
|
+
cwd: string,
|
|
27
|
+
): Promise<InlineSource[]> {
|
|
28
|
+
if (positional.length > 0) {
|
|
29
|
+
const files = resolveSourceFiles([...positional], cwd);
|
|
30
|
+
if (files.length === 0) {
|
|
31
|
+
throw PragmaError.invalidInput("sources", positional.join(", "), {
|
|
32
|
+
recovery: {
|
|
33
|
+
message: "No files matched the given paths or glob patterns.",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return files.map((path) => ({
|
|
38
|
+
content: readFileSync(path, "utf-8"),
|
|
39
|
+
format: "turtle" as const,
|
|
40
|
+
path,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const graphs = await resolveConfiguredGraphs(cwd);
|
|
45
|
+
if (graphs.length === 0) {
|
|
46
|
+
throw PragmaError.invalidInput("sources", "(none)", {
|
|
47
|
+
recovery: {
|
|
48
|
+
message:
|
|
49
|
+
"No TTL sources given and no semantic packages resolved. Pass TTL files or globs, or configure `packages` in pragma.config.json and install them.",
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return graphs.map((graph) => ({
|
|
54
|
+
content: graph.content,
|
|
55
|
+
format: graph.format,
|
|
56
|
+
path: graph.path,
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/** @module Barrel for graphql helpers. */
|
|
2
2
|
|
|
3
|
+
export { default as gatherSources } from "./gatherSources.js";
|
|
3
4
|
export { default as parsePrefixes } from "./parsePrefixes.js";
|
|
4
5
|
export { default as resolveSourceFiles } from "./resolveSourceFiles.js";
|
|
6
|
+
export { default as routeGraphql } from "./routeGraphql.js";
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_PREFIX_MAP } from "../../shared/prefixes.js";
|
|
3
3
|
import parsePrefixes from "./parsePrefixes.js";
|
|
4
4
|
|
|
5
5
|
describe("parsePrefixes", () => {
|
|
6
6
|
it("returns the default prefix map for no entries", () => {
|
|
7
7
|
const prefixes = parsePrefixes([]);
|
|
8
|
-
expect(prefixes).toEqual(
|
|
8
|
+
expect(prefixes).toEqual(DEFAULT_PREFIX_MAP);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it("merges entries on top of the defaults", () => {
|
|
12
12
|
const prefixes = parsePrefixes(["ex=http://example.org/"]);
|
|
13
13
|
expect(prefixes.ex).toBe("http://example.org/");
|
|
14
|
-
expect(prefixes.ds).toBe(
|
|
14
|
+
expect(prefixes.ds).toBe(DEFAULT_PREFIX_MAP.ds);
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
it("lets entries override default prefixes", () => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { PragmaError } from "#error";
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_PREFIX_MAP } from "../../shared/prefixes.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Parse repeated `--prefix name=namespace` entries into a prefix map.
|
|
6
6
|
*
|
|
7
7
|
* User-supplied prefixes are merged on top of pragma's default
|
|
8
|
-
* {@link
|
|
8
|
+
* {@link DEFAULT_PREFIX_MAP}, so `ds:` and the W3C vocabularies stay available
|
|
9
9
|
* unless explicitly overridden.
|
|
10
10
|
*
|
|
11
11
|
* @param entries - Raw `name=namespace` strings from the CLI.
|
|
@@ -15,7 +15,7 @@ import { PREFIX_MAP } from "../../shared/prefixes.js";
|
|
|
15
15
|
export default function parsePrefixes(
|
|
16
16
|
entries: readonly string[],
|
|
17
17
|
): Record<string, string> {
|
|
18
|
-
const prefixes: Record<string, string> = { ...
|
|
18
|
+
const prefixes: Record<string, string> = { ...DEFAULT_PREFIX_MAP };
|
|
19
19
|
|
|
20
20
|
for (const entry of entries) {
|
|
21
21
|
const separator = entry.indexOf("=");
|
|
@@ -53,4 +53,13 @@ describe("resolveSourceFiles", () => {
|
|
|
53
53
|
const files = resolveSourceFiles(["b.ttl", "nested/*.ttl"], dir);
|
|
54
54
|
expect(files).toEqual([join(dir, "b.ttl"), join(dir, "nested", "c.ttl")]);
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
it("skips a directory path instead of treating it as a file", () => {
|
|
58
|
+
// A directory would later crash readFileSync with EISDIR.
|
|
59
|
+
expect(resolveSourceFiles(["nested"], dir)).toEqual([]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("resolves the empty string (the cwd directory) to no files", () => {
|
|
63
|
+
expect(resolveSourceFiles([""], dir)).toEqual([]);
|
|
64
|
+
});
|
|
56
65
|
});
|
|
@@ -8,9 +8,27 @@
|
|
|
8
8
|
* @note Impure — reads filesystem to expand globs and check existence.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { globSync, statSync } from "node:fs";
|
|
12
12
|
import { resolve } from "node:path";
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Whether a path points at an existing regular file.
|
|
16
|
+
*
|
|
17
|
+
* Guards against a directory (or the empty-string path, which resolves to the
|
|
18
|
+
* cwd directory) slipping through as a "source" and later crashing readFileSync
|
|
19
|
+
* with EISDIR.
|
|
20
|
+
*
|
|
21
|
+
* @param absPath - Absolute path to check.
|
|
22
|
+
* @returns True when the path exists and is a regular file.
|
|
23
|
+
*/
|
|
24
|
+
function isRegularFile(absPath: string): boolean {
|
|
25
|
+
try {
|
|
26
|
+
return statSync(absPath).isFile();
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
14
32
|
/**
|
|
15
33
|
* Expand file paths and glob patterns into absolute file paths.
|
|
16
34
|
*
|
|
@@ -31,11 +49,14 @@ export default function resolveSourceFiles(
|
|
|
31
49
|
pattern.includes("[")
|
|
32
50
|
) {
|
|
33
51
|
for (const file of globSync(pattern, { cwd })) {
|
|
34
|
-
|
|
52
|
+
const absPath = resolve(cwd, file);
|
|
53
|
+
if (isRegularFile(absPath)) {
|
|
54
|
+
files.push(absPath);
|
|
55
|
+
}
|
|
35
56
|
}
|
|
36
57
|
} else {
|
|
37
58
|
const absPath = resolve(cwd, pattern);
|
|
38
|
-
if (
|
|
59
|
+
if (isRegularFile(absPath)) {
|
|
39
60
|
files.push(absPath);
|
|
40
61
|
}
|
|
41
62
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import routeGraphql from "./routeGraphql.js";
|
|
3
|
+
|
|
4
|
+
describe("routeGraphql", () => {
|
|
5
|
+
it("delegates /graphql to the handler", async () => {
|
|
6
|
+
const handler = vi.fn(() => new Response("handled"));
|
|
7
|
+
const request = new Request("http://localhost:4000/graphql");
|
|
8
|
+
|
|
9
|
+
const response = await routeGraphql(request, handler, 4000);
|
|
10
|
+
|
|
11
|
+
expect(handler).toHaveBeenCalledWith(request);
|
|
12
|
+
expect(await response.text()).toBe("handled");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("redirects / to /graphql", async () => {
|
|
16
|
+
const handler = vi.fn();
|
|
17
|
+
|
|
18
|
+
const response = await routeGraphql(
|
|
19
|
+
new Request("http://localhost:4000/"),
|
|
20
|
+
handler,
|
|
21
|
+
4000,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
expect(response.status).toBe(302);
|
|
25
|
+
expect(response.headers.get("location")).toBe(
|
|
26
|
+
"http://localhost:4000/graphql",
|
|
27
|
+
);
|
|
28
|
+
expect(handler).not.toHaveBeenCalled();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("404s any other path", async () => {
|
|
32
|
+
const handler = vi.fn();
|
|
33
|
+
|
|
34
|
+
const response = await routeGraphql(
|
|
35
|
+
new Request("http://localhost:4000/favicon.ico"),
|
|
36
|
+
handler,
|
|
37
|
+
4000,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
expect(response.status).toBe(404);
|
|
41
|
+
expect(handler).not.toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route an incoming request for the graphql dev server: `/graphql` to the
|
|
3
|
+
* GraphQL + GraphiQL handler, `/` to a redirect there, and everything else
|
|
4
|
+
* to 404. Mounting is intentionally the host's job, which keeps the handler
|
|
5
|
+
* itself path-agnostic.
|
|
6
|
+
*
|
|
7
|
+
* @param request - The incoming fetch Request.
|
|
8
|
+
* @param handler - The GraphQL fetch handler for `/graphql`.
|
|
9
|
+
* @param port - The listen port, used to build the root redirect target.
|
|
10
|
+
* @returns The response (or a promise of one) for the route.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
type GraphQLHandler = (request: Request) => Response | Promise<Response>;
|
|
14
|
+
|
|
15
|
+
export default function routeGraphql(
|
|
16
|
+
request: Request,
|
|
17
|
+
handler: GraphQLHandler,
|
|
18
|
+
port: number,
|
|
19
|
+
): Response | Promise<Response> {
|
|
20
|
+
const { pathname } = new URL(request.url);
|
|
21
|
+
if (pathname === "/graphql") {
|
|
22
|
+
return handler(request);
|
|
23
|
+
}
|
|
24
|
+
if (pathname === "/") {
|
|
25
|
+
return Response.redirect(`http://localhost:${port}/graphql`, 302);
|
|
26
|
+
}
|
|
27
|
+
return new Response(null, { status: 404 });
|
|
28
|
+
}
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module GraphQL domain barrel.
|
|
3
3
|
*
|
|
4
|
-
* Compiles TTL ontologies into GraphQL schema artifacts via the
|
|
5
|
-
*
|
|
6
|
-
* TTL sources,
|
|
4
|
+
* Compiles TTL ontologies into GraphQL schema artifacts via the ke-graphql
|
|
5
|
+
* pipeline, and serves them locally. Commands boot their own ke store —
|
|
6
|
+
* from explicit TTL sources or, when none are given, the semantic packages
|
|
7
|
+
* configured in `pragma.config.json` — so they run on the store-skip
|
|
8
|
+
* pipeline path.
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
11
|
import type { CommandDefinition } from "@canonical/cli-core";
|
|
10
|
-
import { buildCommand, checkCommand } from "./commands/index.js";
|
|
12
|
+
import { buildCommand, checkCommand, serveCommand } from "./commands/index.js";
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Returns all command definitions for the graphql domain.
|
|
14
16
|
*
|
|
15
|
-
* @returns
|
|
17
|
+
* @returns The `graphql build`, `graphql check`, and `graphql serve`
|
|
18
|
+
* command definitions.
|
|
16
19
|
*/
|
|
17
20
|
export function commands(): CommandDefinition[] {
|
|
18
|
-
return [buildCommand, checkCommand];
|
|
21
|
+
return [buildCommand, checkCommand, serveCommand];
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
export { compileSchema } from "./operations/index.js";
|
|
@@ -1,73 +1,57 @@
|
|
|
1
|
-
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
1
|
import { hashSources } from "@canonical/ke-graphql";
|
|
5
|
-
import {
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
6
3
|
import {
|
|
7
4
|
EX_NAMESPACE,
|
|
8
5
|
GRAPHQL_CLEAN_TTL,
|
|
9
6
|
GRAPHQL_ERROR_TTL,
|
|
10
7
|
GRAPHQL_FATAL_TTL,
|
|
11
8
|
} from "#testing";
|
|
12
|
-
import {
|
|
9
|
+
import { DEFAULT_PREFIX_MAP } from "../../shared/prefixes.js";
|
|
13
10
|
import compileSchema from "./compileSchema.js";
|
|
14
11
|
|
|
15
|
-
const PREFIXES = { ...
|
|
12
|
+
const PREFIXES = { ...DEFAULT_PREFIX_MAP, ex: EX_NAMESPACE };
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
writeFileSync(join(dir, "clean.ttl"), GRAPHQL_CLEAN_TTL);
|
|
23
|
-
writeFileSync(join(dir, "error.ttl"), GRAPHQL_ERROR_TTL);
|
|
24
|
-
writeFileSync(join(dir, "fatal.ttl"), GRAPHQL_FATAL_TTL);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
afterEach(() => {
|
|
28
|
-
rmSync(dir, { recursive: true, force: true });
|
|
29
|
-
});
|
|
14
|
+
const inline = (content: string, path: string) => ({
|
|
15
|
+
content,
|
|
16
|
+
format: "turtle" as const,
|
|
17
|
+
path,
|
|
18
|
+
});
|
|
30
19
|
|
|
20
|
+
describe("compileSchema", () => {
|
|
31
21
|
it("compiles a clean ontology into SDL", async () => {
|
|
32
22
|
const outcome = await compileSchema({
|
|
33
|
-
sources: ["clean.ttl"],
|
|
23
|
+
sources: [inline(GRAPHQL_CLEAN_TTL, "clean.ttl")],
|
|
34
24
|
prefixes: PREFIXES,
|
|
35
|
-
cwd: dir,
|
|
36
25
|
});
|
|
37
26
|
|
|
38
27
|
expect(outcome.status).toBe("ok");
|
|
39
28
|
expect(outcome.compiled?.sdl).toContain("type Thing");
|
|
40
29
|
expect(outcome.diagnostics).toEqual([]);
|
|
41
|
-
expect(outcome.files).toEqual([
|
|
30
|
+
expect(outcome.files).toEqual(["clean.ttl"]);
|
|
42
31
|
});
|
|
43
32
|
|
|
44
|
-
it("hashes the exact raw
|
|
33
|
+
it("hashes the exact raw source contents", async () => {
|
|
45
34
|
const outcome = await compileSchema({
|
|
46
|
-
sources: ["clean.ttl"],
|
|
35
|
+
sources: [inline(GRAPHQL_CLEAN_TTL, "clean.ttl")],
|
|
47
36
|
prefixes: PREFIXES,
|
|
48
|
-
cwd: dir,
|
|
49
37
|
});
|
|
50
38
|
|
|
51
|
-
|
|
52
|
-
expect(outcome.sourcesHash).toBe(hashSources([raw]));
|
|
39
|
+
expect(outcome.sourcesHash).toBe(hashSources([GRAPHQL_CLEAN_TTL]));
|
|
53
40
|
});
|
|
54
41
|
|
|
55
|
-
it("
|
|
42
|
+
it("labels a source without a path as 'inline'", async () => {
|
|
56
43
|
const outcome = await compileSchema({
|
|
57
|
-
sources: ["
|
|
44
|
+
sources: [{ content: GRAPHQL_CLEAN_TTL, format: "turtle" }],
|
|
58
45
|
prefixes: PREFIXES,
|
|
59
|
-
cwd: dir,
|
|
60
46
|
});
|
|
61
47
|
|
|
62
|
-
expect(outcome.
|
|
63
|
-
expect(outcome.files).toEqual([join(dir, "clean.ttl")]);
|
|
48
|
+
expect(outcome.files).toEqual(["inline"]);
|
|
64
49
|
});
|
|
65
50
|
|
|
66
51
|
it("surfaces error diagnostics without failing the compile", async () => {
|
|
67
52
|
const outcome = await compileSchema({
|
|
68
|
-
sources: ["error.ttl"],
|
|
53
|
+
sources: [inline(GRAPHQL_ERROR_TTL, "error.ttl")],
|
|
69
54
|
prefixes: PREFIXES,
|
|
70
|
-
cwd: dir,
|
|
71
55
|
});
|
|
72
56
|
|
|
73
57
|
expect(outcome.status).toBe("ok");
|
|
@@ -81,9 +65,8 @@ describe("compileSchema", () => {
|
|
|
81
65
|
|
|
82
66
|
it("converts CompilationError into a failed result with diagnostics", async () => {
|
|
83
67
|
const outcome = await compileSchema({
|
|
84
|
-
sources: ["fatal.ttl"],
|
|
68
|
+
sources: [inline(GRAPHQL_FATAL_TTL, "fatal.ttl")],
|
|
85
69
|
prefixes: PREFIXES,
|
|
86
|
-
cwd: dir,
|
|
87
70
|
});
|
|
88
71
|
|
|
89
72
|
expect(outcome.status).toBe("failed");
|
|
@@ -95,24 +78,17 @@ describe("compileSchema", () => {
|
|
|
95
78
|
).toBe(true);
|
|
96
79
|
});
|
|
97
80
|
|
|
98
|
-
it("throws structured error when no sources
|
|
81
|
+
it("throws a structured error when given no sources", async () => {
|
|
99
82
|
await expect(
|
|
100
|
-
compileSchema({
|
|
101
|
-
sources: ["missing.ttl"],
|
|
102
|
-
prefixes: PREFIXES,
|
|
103
|
-
cwd: dir,
|
|
104
|
-
}),
|
|
83
|
+
compileSchema({ sources: [], prefixes: PREFIXES }),
|
|
105
84
|
).rejects.toMatchObject({ code: "INVALID_INPUT" });
|
|
106
85
|
});
|
|
107
86
|
|
|
108
|
-
it("throws structured error on invalid TTL syntax", async () => {
|
|
109
|
-
writeFileSync(join(dir, "broken.ttl"), "this is not turtle .");
|
|
110
|
-
|
|
87
|
+
it("throws a structured error on invalid TTL syntax", async () => {
|
|
111
88
|
await expect(
|
|
112
89
|
compileSchema({
|
|
113
|
-
sources: ["broken.ttl"],
|
|
90
|
+
sources: [inline("this is not turtle .", "broken.ttl")],
|
|
114
91
|
prefixes: PREFIXES,
|
|
115
|
-
cwd: dir,
|
|
116
92
|
}),
|
|
117
93
|
).rejects.toMatchObject({ code: "STORE_ERROR" });
|
|
118
94
|
});
|