@astryxdesign/cli 0.7.2 → 0.7.3-canary.02f5fe4
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 +104 -71
- package/api/build/_adapter.d.mts +58 -0
- package/api/build/_adapter.mjs +127 -3
- package/api/build/blocks/blocks.d.mts +92 -0
- package/api/build/blocks/blocks.mjs +528 -0
- package/api/build/blocks/blocks.test.mjs +238 -0
- package/api/build/blocks/blocks.weights.json +1 -0
- package/api/build/build.mjs +25 -6
- package/api/build/build.type.mjs +1 -1
- package/api/build/kit/answer.d.mts +18 -0
- package/api/build/kit/answer.mjs +195 -0
- package/api/build/kit/answer.test.mjs +108 -0
- package/api/build/kit/kind.d.mts +25 -0
- package/api/build/kit/kind.mjs +170 -0
- package/api/build/kit/kit.d.mts +2 -4
- package/api/build/kit/kit.mjs +8 -398
- package/api/build/kit/rank.d.mts +3 -32
- package/api/build/kit/rank.mjs +25 -342
- package/api/build/kit/rank.test.mjs +2 -1
- package/api/build/kit/signals.d.mts +79 -0
- package/api/build/kit/signals.mjs +295 -0
- package/api/build/kit/start.d.mts +32 -0
- package/api/build/kit/start.mjs +163 -0
- package/api/build/kit/words.d.mts +72 -0
- package/api/build/kit/words.mjs +202 -0
- package/api/build/tree.d.mts +20 -0
- package/api/build/tree.mjs +53 -0
- package/api/build/tree.test.mjs +185 -0
- package/api/build/tree.weights.json +1 -0
- package/api/component/_adapter.mjs +39 -5
- package/api/component/component-replacement.test.mjs +1 -0
- package/api/component/component.mjs +17 -3
- package/api/component/component.test.mjs +15 -0
- package/api/component/doc-links.test.mjs +2 -2
- package/api/discover/_adapter.d.mts +1 -2
- package/api/discover/_adapter.mjs +42 -17
- package/api/discover/_adapter.test.mjs +42 -0
- package/api/discover/discover.mjs +0 -1
- package/api/docs/_adapter.d.mts +2 -2
- package/api/docs/_adapter.mjs +82 -23
- package/api/docs/docs-homes.test.mjs +127 -0
- package/api/docs/docs.doc.mjs +3 -3
- package/api/docs/docs.test.mjs +35 -19
- package/api/docs/integration-tree.test.mjs +20 -20
- package/api/docs/integrationDocs.test.mjs +1 -1
- package/api/docs/namespace-section.test.mjs +6 -6
- package/api/docs/reference-blocks.test.mjs +2 -2
- package/api/doctor/_adapter.d.mts +33 -13
- package/api/doctor/_adapter.mjs +55 -25
- package/api/doctor/doctor.d.mts +23 -5
- package/api/doctor/doctor.mjs +183 -40
- package/api/doctor/doctor.test.mjs +95 -12
- package/api/hook/hook.mjs +1 -1
- package/api/init/init.doc.mjs +20 -6
- package/api/init/init.test.mjs +18 -2
- package/api/init/init.type.d.mts +3 -3
- package/api/init/init.type.mjs +3 -3
- package/api/init/remove/remove.mjs +17 -4
- package/api/init/remove/remove.test.mjs +114 -2
- package/api/init/run/run.mjs +69 -6
- package/api/integration/_adapter.d.mts +8 -0
- package/api/integration/_adapter.mjs +21 -1
- package/api/integration/authoring-checks.mjs +83 -9
- package/api/integration/authoring-checks.test.mjs +220 -0
- package/api/integration/pack-check.mjs +123 -4
- package/api/integration/pack-check.test.mjs +87 -0
- package/api/integration/validate-integration-case-disk.test.mjs +111 -0
- package/api/integration/validate-integration-fixes.test.mjs +6 -5
- package/api/integration/validate-integration-gaps.test.mjs +1975 -0
- package/api/integration/validate-integration.d.mts +15 -2
- package/api/integration/validate-integration.mjs +298 -39
- package/api/integration/validate-integration.type.d.mts +90 -1
- package/api/integration/validate-integration.type.mjs +67 -2
- package/api/integration/validateIntegration.doc.mjs +1 -1
- package/api/search/ORDERING.md +28 -0
- package/api/search/_adapter.d.mts +82 -2
- package/api/search/_adapter.mjs +157 -10
- package/api/search/_adapter.test.mjs +173 -0
- package/api/search/_candidate-score.d.mts +40 -0
- package/api/search/_candidate-score.mjs +238 -0
- package/api/search/_cards.json +6098 -0
- package/api/search/_compound.d.mts +50 -0
- package/api/search/_compound.mjs +170 -0
- package/api/search/_doc-searcher.d.mts +4 -0
- package/api/search/_doc-searcher.mjs +23 -0
- package/api/search/_doc-searcher.test.mjs +36 -0
- package/api/search/_doc-searcher.weights.json +1 -0
- package/api/search/_doc-text.d.mts +30 -0
- package/api/search/_doc-text.mjs +87 -0
- package/api/search/_entries.d.mts +63 -0
- package/api/search/_entries.mjs +232 -0
- package/api/search/_entries.test.mjs +48 -0
- package/api/search/_features.d.mts +35 -0
- package/api/search/_features.mjs +155 -0
- package/api/search/_gather-components.d.mts +26 -0
- package/api/search/_gather-components.mjs +284 -0
- package/api/search/_gather-docs.d.mts +20 -0
- package/api/search/_gather-docs.mjs +254 -0
- package/api/search/_gather-hooks.d.mts +12 -0
- package/api/search/_gather-hooks.mjs +52 -0
- package/api/search/_gather-templates.d.mts +25 -0
- package/api/search/_gather-templates.mjs +107 -0
- package/api/search/_lexical.d.mts +135 -0
- package/api/search/_lexical.mjs +351 -0
- package/api/search/_main-searcher.d.mts +19 -0
- package/api/search/_main-searcher.mjs +115 -0
- package/api/search/_main-searcher.test.mjs +106 -0
- package/api/search/_main-searcher.weights.json +1 -0
- package/api/search/_module-doc.d.mts +32 -0
- package/api/search/_module-doc.mjs +78 -0
- package/api/search/_order.d.mts +32 -0
- package/api/search/_order.mjs +162 -0
- package/api/search/_order.test.mjs +72 -0
- package/api/search/_priority.d.mts +50 -0
- package/api/search/_priority.mjs +139 -0
- package/api/search/_query-words.d.mts +25 -0
- package/api/search/_query-words.mjs +92 -0
- package/api/search/_query.d.mts +65 -0
- package/api/search/_query.mjs +176 -0
- package/api/search/_result.d.mts +97 -0
- package/api/search/_result.mjs +150 -0
- package/api/search/_score.d.mts +60 -0
- package/api/search/_score.mjs +283 -0
- package/api/search/_synonyms.d.mts +21 -0
- package/api/search/_synonyms.mjs +67 -0
- package/api/search/_template-searcher.d.mts +4 -0
- package/api/search/_template-searcher.mjs +23 -0
- package/api/search/_template-searcher.test.mjs +40 -0
- package/api/search/_template-searcher.weights.json +1 -0
- package/api/search/_titles.d.mts +33 -0
- package/api/search/_titles.mjs +65 -0
- package/api/search/_words.d.mts +64 -0
- package/api/search/_words.mjs +157 -0
- package/api/search/search.d.mts +22 -305
- package/api/search/search.doc.mjs +8 -6
- package/api/search/search.mjs +56 -2482
- package/api/search/search.test.mjs +14 -14
- package/api/search/search.type.d.mts +6 -1
- package/api/search/search.type.mjs +6 -1
- package/api/search/tree.d.mts +15 -0
- package/api/search/tree.mjs +40 -0
- package/api/search/tree.test.mjs +66 -0
- package/api/search/tree.weights.json +1 -0
- package/api/template/template.mjs +5 -1
- package/api/theme/build/build.packed-old-core.test.mjs +1 -0
- package/api/upgrade/_adapter.d.mts +57 -9
- package/api/upgrade/_adapter.mjs +198 -28
- package/api/upgrade/registry/registry.d.mts +10 -4
- package/api/upgrade/registry/registry.mjs +33 -16
- package/api/upgrade/registry/registry.test.mjs +85 -0
- package/api/upgrade/run/run.d.mts +4 -2
- package/api/upgrade/run/run.mjs +13 -2
- package/api/upgrade/run/run.test.mjs +417 -3
- package/api/upgrade/upgrade.doc.mjs +10 -5
- package/api/upgrade/upgrade.mjs +13 -2
- package/api/upgrade/upgrade.test.mjs +194 -0
- package/api/upgrade/upgrade.type.d.mts +5 -3
- package/api/upgrade/upgrade.type.mjs +8 -6
- package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
- package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
- package/assets/docs/author-a-theme.doc.mjs +2 -2
- package/assets/docs/is-my-code-good.doc.mjs +287 -0
- package/assets/docs/tree/add-a-component.doc.mjs +1 -1
- package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
- package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +6 -0
- package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
- package/assets/docs/tree/block-template.doc.mjs +1 -1
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +2 -2
- package/assets/docs/tree/check-the-props.doc.mjs +1 -1
- package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
- package/assets/docs/tree/checks.doc.mjs +3 -3
- package/assets/docs/tree/ci-and-containers.doc.mjs +13 -0
- package/assets/docs/tree/cli-command.doc.mjs +1 -1
- package/assets/docs/tree/cli.doc.mjs +1 -1
- package/assets/docs/tree/codemods.doc.mjs +1 -1
- package/assets/docs/tree/component-family.doc.mjs +1 -1
- package/assets/docs/tree/component-imports.doc.mjs +1 -1
- package/assets/docs/tree/components.doc.mjs +1 -1
- package/assets/docs/tree/configuration.doc.mjs +1 -1
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
- package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
- package/assets/docs/tree/docs.doc.mjs +1 -1
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
- package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
- package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
- package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
- package/assets/docs/tree/global-integrations.doc.mjs +2 -2
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
- package/assets/docs/tree/help.doc.mjs +2 -2
- package/assets/docs/tree/host-entry.doc.mjs +128 -0
- package/assets/docs/tree/links.doc.mjs +1 -1
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +1 -1
- package/assets/docs/tree/publishing.doc.mjs +1 -1
- package/assets/docs/tree/quick-start.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/ship.doc.mjs +2 -2
- package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
- package/assets/docs/tree/single-component.doc.mjs +1 -1
- package/assets/docs/tree/start-a-template.doc.mjs +1 -1
- package/assets/docs/tree/subcomponent.doc.mjs +1 -1
- package/assets/docs/tree/template-assets.doc.mjs +1 -1
- package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
- package/assets/docs/tree/template-icons.doc.mjs +1 -1
- package/assets/docs/tree/template-images-media.doc.mjs +1 -1
- package/assets/docs/tree/template-styles.doc.mjs +1 -1
- package/assets/docs/tree/templates.doc.mjs +1 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
- package/assets/docs/tree/themes.doc.mjs +1 -1
- package/assets/docs/tree/tokens-data.doc.mjs +2 -2
- package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
- package/assets/docs/tree/upgrading.doc.mjs +1 -1
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
- package/assets/docs/tree/versioning.doc.mjs +5 -1
- package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
- package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
- package/assets/docs/use-integrations.doc.mjs +120 -0
- package/assets/docs/working-with-ai.doc.mjs +6 -2
- package/assets/templates/themes/butter/butterTheme.ts +4 -2
- package/assets/templates/themes/stone/stoneTheme.ts +4 -2
- package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
- package/authoring/debug/parse.d.mts +1 -1
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/integration/integration.doc.mjs +1 -1
- package/authoring/integration/type.ts +1 -1
- package/clients/cli/bin/astryx.mjs +7 -78
- package/clients/cli/command-result-coverage.test.mjs +6 -5
- package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
- package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
- package/clients/cli/commands/component.test.mjs +6 -6
- package/clients/cli/commands/docs.doc.mjs +2 -2
- package/clients/cli/commands/docs.mjs +1 -1
- package/clients/cli/commands/docs.test.mjs +14 -14
- package/clients/cli/commands/doctor-integration.test.mjs +49 -1
- package/clients/cli/commands/doctor.doc.mjs +1 -1
- package/clients/cli/commands/doctor.mjs +40 -0
- package/clients/cli/commands/doctor.test.mjs +65 -0
- package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
- package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
- package/clients/cli/commands/init.behavior.test.mjs +230 -1
- package/clients/cli/commands/init.doc.mjs +28 -9
- package/clients/cli/commands/init.flag-help.test.mjs +1 -0
- package/clients/cli/commands/init.mjs +2 -2
- package/clients/cli/commands/integration-check.test.mjs +48 -0
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/manifest.mjs +67 -0
- package/clients/cli/commands/outside-project.test.mjs +101 -1
- package/clients/cli/commands/postinstall.doc.mjs +23 -0
- package/clients/cli/commands/postinstall.mjs +31 -0
- package/clients/cli/commands/setup-nudge.test.mjs +78 -0
- package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
- package/clients/cli/commands/upgrade.doc.mjs +4 -2
- package/clients/cli/commands/upgrade.mjs +9 -2
- package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
- package/clients/cli/index.mjs +54 -94
- package/clients/cli/lib/component-format.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +12 -7
- package/clients/cli/lib/exit-codes.test.mjs +5 -0
- package/clients/cli/lib/manifest.test.mjs +12 -0
- package/clients/cli/lib/welcome-box.mjs +50 -0
- package/clients/cli/run.mjs +108 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +32 -7
- package/foundation/agent-docs/agent-doc-state.mjs +58 -9
- package/foundation/agent-docs/agent-docs.d.mts +100 -12
- package/foundation/agent-docs/agent-docs.mjs +1017 -105
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
- package/foundation/agent-docs/agent-docs.test.mjs +683 -39
- package/foundation/agent-docs/computer-agent-text.d.mts +39 -2
- package/foundation/agent-docs/computer-agent-text.mjs +135 -8
- package/foundation/agent-docs/computer-agent-text.test.mjs +99 -2
- package/foundation/config/project.mjs +20 -22
- package/foundation/config/project.test.mjs +56 -0
- package/foundation/discovery/authoring-self-docs.d.mts +7 -0
- package/foundation/discovery/authoring-self-docs.mjs +16 -4
- package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
- package/foundation/discovery/authoring-surface.d.mts +1 -1
- package/foundation/discovery/authoring-surface.mjs +2 -2
- package/foundation/discovery/authoring-surface.test.mjs +1 -1
- package/foundation/discovery/cli-self-docs.d.mts +2 -1
- package/foundation/discovery/cli-self-docs.mjs +4 -3
- package/foundation/discovery/cli-self-docs.test.mjs +2 -2
- package/foundation/discovery/component-discovery.d.mts +37 -0
- package/foundation/discovery/component-discovery.mjs +80 -5
- package/foundation/discovery/component-loader.d.mts +1 -1
- package/foundation/discovery/docs-discovery.mjs +14 -1
- package/foundation/discovery/module-exports.d.mts +41 -0
- package/foundation/discovery/module-exports.mjs +253 -0
- package/foundation/discovery/runner-allowlist.d.mts +2 -4
- package/foundation/discovery/runner-allowlist.mjs +2 -4
- package/foundation/discovery/runner-commands.d.mts +77 -0
- package/foundation/discovery/runner-commands.mjs +294 -0
- package/foundation/discovery/runner-commands.test.mjs +128 -0
- package/foundation/discovery/stray-pointers.test.mjs +1 -1
- package/foundation/discovery/template-adapter.mjs +18 -1
- package/foundation/discovery/template-needs.mjs +1 -44
- package/foundation/discovery/theme-discovery.mjs +147 -3
- package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
- package/foundation/doc-compiler/read.mjs +59 -1
- package/foundation/doc-compiler/read.test.mjs +11 -2
- package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
- package/foundation/doc-compiler/tree.d.mts +32 -6
- package/foundation/doc-compiler/tree.mjs +77 -43
- package/foundation/doc-compiler/tree.test.mjs +7 -7
- package/foundation/fs/paths.d.mts +70 -8
- package/foundation/fs/paths.mjs +556 -38
- package/foundation/fs/paths.test.mjs +430 -54
- package/foundation/fs/read-record.d.mts +18 -0
- package/foundation/fs/read-record.mjs +131 -0
- package/foundation/fs/read-record.test.mjs +77 -0
- package/foundation/integrations/autolink.d.mts +2 -1
- package/foundation/integrations/autolink.mjs +4 -13
- package/foundation/integrations/cli-peer-version.d.mts +36 -0
- package/foundation/integrations/cli-peer-version.mjs +132 -0
- package/foundation/integrations/cli-peer-version.test.mjs +354 -0
- package/foundation/integrations/computer-integrations.d.mts +6 -3
- package/foundation/integrations/computer-integrations.mjs +38 -9
- package/foundation/integrations/contribution-inventory.d.mts +15 -20
- package/foundation/integrations/contribution-inventory.mjs +41 -5
- package/foundation/integrations/exports-subpaths.d.mts +57 -0
- package/foundation/integrations/exports-subpaths.mjs +113 -0
- package/foundation/integrations/integrations.d.mts +27 -1
- package/foundation/integrations/integrations.mjs +61 -2
- package/foundation/integrations/public-imports.d.mts +118 -0
- package/foundation/integrations/public-imports.mjs +1769 -0
- package/foundation/integrations/public-imports.test.mjs +1793 -0
- package/foundation/integrations/validate-contributions.d.mts +115 -0
- package/foundation/integrations/validate-contributions.mjs +1168 -13
- package/foundation/release/cache.test.mjs +24 -21
- package/foundation/release/global-state.d.mts +8 -4
- package/foundation/release/global-state.mjs +4 -2
- package/foundation/release/handoff.d.mts +23 -4
- package/foundation/release/handoff.mjs +175 -8
- package/foundation/release/notices.d.mts +62 -8
- package/foundation/release/notices.mjs +136 -25
- package/foundation/release/notices.test.mjs +21 -0
- package/foundation/release/run-context.mjs +14 -0
- package/foundation/response/response-types.doc.mjs +1 -1
- package/foundation/route/route.d.mts +285 -0
- package/foundation/route/route.mjs +324 -0
- package/foundation/route/route.test.mjs +153 -0
- package/foundation/runtime/hosted-runtime.test.mjs +403 -0
- package/foundation/runtime/locked-versions.d.mts +32 -0
- package/foundation/runtime/locked-versions.mjs +65 -0
- package/foundation/runtime/package-root.d.mts +91 -0
- package/foundation/runtime/package-root.mjs +174 -0
- package/foundation/runtime/package-set.d.mts +62 -0
- package/foundation/runtime/package-set.mjs +130 -0
- package/foundation/runtime/package-set.test.mjs +432 -0
- package/foundation/text/string-utils.d.mts +2 -1
- package/foundation/text/string-utils.mjs +16 -5
- package/foundation/text/suggest-order.d.mts +72 -0
- package/foundation/text/suggest-order.mjs +363 -0
- package/foundation/text/suggest-order.test.mjs +259 -0
- package/host/door-conformance.test.mjs +274 -0
- package/host/index.d.ts +116 -0
- package/host/index.mjs +295 -0
- package/host/index.test.mjs +302 -0
- package/package.json +14 -9
|
@@ -25,6 +25,8 @@ import {
|
|
|
25
25
|
availableComputerIntegrations,
|
|
26
26
|
} from '../../foundation/config/project.mjs';
|
|
27
27
|
import {isOutsideProject} from '../../foundation/env/project-scope.mjs';
|
|
28
|
+
import {projectAddCommand} from '../../foundation/release/notices.mjs';
|
|
29
|
+
import {hostedRun} from '../../foundation/runtime/package-root.mjs';
|
|
28
30
|
import {
|
|
29
31
|
scanAllPackages,
|
|
30
32
|
findComponentInPackages,
|
|
@@ -242,6 +244,7 @@ export async function describeInstalled(project, scanned) {
|
|
|
242
244
|
* @returns {boolean}
|
|
243
245
|
*/
|
|
244
246
|
export function hasSources(project) {
|
|
247
|
+
if (doorSources().length > 0) return true;
|
|
245
248
|
if (project == null) return false;
|
|
246
249
|
if (typeof project.config?.discover === 'function') return true;
|
|
247
250
|
return project.loadedIntegrations.some(
|
|
@@ -249,6 +252,19 @@ export function hasSources(project) {
|
|
|
249
252
|
);
|
|
250
253
|
}
|
|
251
254
|
|
|
255
|
+
/** Where a discover source a host passed comes from (spec AST-081 FR1). */
|
|
256
|
+
const DOOR_SOURCE = 'the host';
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* The discover sources the host that started this run passed, if any.
|
|
260
|
+
* @returns {readonly DiscoverSource[]}
|
|
261
|
+
*/
|
|
262
|
+
function doorSources() {
|
|
263
|
+
return /** @type {readonly DiscoverSource[]} */ (
|
|
264
|
+
hostedRun()?.discoverSources ?? []
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
252
268
|
/** The source name of a package installed for the computer. */
|
|
253
269
|
const COMPUTER_SOURCE = 'installed for this computer';
|
|
254
270
|
|
|
@@ -259,17 +275,14 @@ const COMPUTER_SOURCE = 'installed for this computer';
|
|
|
259
275
|
* @param {Project | undefined} project
|
|
260
276
|
* @param {Array<{name: string}>} installed
|
|
261
277
|
* @param {Set<string>} declared
|
|
262
|
-
* @param {(name: string, version?: string) => string} add
|
|
263
278
|
* @returns {Promise<import('./discover.type.mjs').DiscoverAvailableEntry[]>}
|
|
264
279
|
*/
|
|
265
|
-
export async function computerAvailableEntries(
|
|
266
|
-
project,
|
|
267
|
-
installed,
|
|
268
|
-
declared,
|
|
269
|
-
add,
|
|
270
|
-
) {
|
|
280
|
+
export async function computerAvailableEntries(project, installed, declared) {
|
|
271
281
|
const cwd = project?.cwd ?? process.cwd();
|
|
272
282
|
if (isOutsideProject(cwd)) return [];
|
|
283
|
+
// The same command doctor names: in the project spec:AST-040 FR9 defines,
|
|
284
|
+
// and none where FR9 finds no project.
|
|
285
|
+
const add = projectAddCommand(cwd);
|
|
273
286
|
const have = new Set([...installed.map(pkg => pkg.name), ...declared]);
|
|
274
287
|
return (await availableComputerIntegrations(cwd, have)).map(c => ({
|
|
275
288
|
name: c.name,
|
|
@@ -277,7 +290,7 @@ export async function computerAvailableEntries(
|
|
|
277
290
|
...(c.version ? {version: c.version} : {}),
|
|
278
291
|
...(c.description ? {description: c.description} : {}),
|
|
279
292
|
source: COMPUTER_SOURCE,
|
|
280
|
-
install: add(c.name),
|
|
293
|
+
...(add ? {install: add(c.name)} : {}),
|
|
281
294
|
}));
|
|
282
295
|
}
|
|
283
296
|
|
|
@@ -479,7 +492,8 @@ export function defaultCacheDir() {
|
|
|
479
492
|
|
|
480
493
|
/**
|
|
481
494
|
* @param {string} cacheDir
|
|
482
|
-
* @param {string} from
|
|
495
|
+
* @param {string} from the source's key: its `from` label, with the host for
|
|
496
|
+
* a host's source
|
|
483
497
|
* @param {{package?: string, version?: string}} request
|
|
484
498
|
*/
|
|
485
499
|
function savedCopyPath(cacheDir, from, request) {
|
|
@@ -557,8 +571,9 @@ async function callSource(source, request, label, timeoutMs) {
|
|
|
557
571
|
}
|
|
558
572
|
|
|
559
573
|
/**
|
|
560
|
-
* Call the
|
|
561
|
-
*
|
|
574
|
+
* Call the discover sources — the project's `discover` first, then each
|
|
575
|
+
* integration's in load order, then each a host passed, named as the host's
|
|
576
|
+
* (spec AST-081 FR1, AST-051 FR6) — once per distinct function. A source that
|
|
562
577
|
* throws, times out, or returns an invalid catalog falls back to its saved copy;
|
|
563
578
|
* with none, it is reported and adds nothing. The others always count.
|
|
564
579
|
*
|
|
@@ -572,20 +587,30 @@ async function callOwnSources(project, request = {}, options = {}) {
|
|
|
572
587
|
const {cacheDir = defaultCacheDir(), timeoutMs = SOURCE_TIMEOUT_MS} = options;
|
|
573
588
|
/** @type {CatalogResult} */
|
|
574
589
|
const result = {sources: [], packages: []};
|
|
575
|
-
|
|
590
|
+
const fromDoor = doorSources();
|
|
591
|
+
if (project == null && fromDoor.length === 0) return result;
|
|
576
592
|
|
|
577
|
-
/** @type {Array<{from: string, source?: DiscoverSource, error?: string}>} */
|
|
593
|
+
/** @type {Array<{from: string, key?: string, source?: DiscoverSource, error?: string}>} */
|
|
578
594
|
const origins = [];
|
|
579
|
-
if (typeof project
|
|
595
|
+
if (typeof project?.config?.discover === 'function') {
|
|
580
596
|
origins.push({from: 'astryx.config', source: project.config.discover});
|
|
581
597
|
}
|
|
582
|
-
for (const integration of project
|
|
598
|
+
for (const integration of project?.loadedIntegrations ?? []) {
|
|
583
599
|
if (integration.__discoverError) {
|
|
584
600
|
origins.push({from: integration.name, error: integration.__discoverError});
|
|
585
601
|
} else if (integration.__discover) {
|
|
586
602
|
origins.push({from: integration.name, source: integration.__discover});
|
|
587
603
|
}
|
|
588
604
|
}
|
|
605
|
+
// Every tool that carries the CLI reports its sources as the host's, so
|
|
606
|
+
// their saved copies are kept per host, by the root that holds its CLI
|
|
607
|
+
// (spec:AST-051 FR8).
|
|
608
|
+
const host = hostedRun()?.startingRoot ?? '';
|
|
609
|
+
fromDoor.forEach((source, index) => {
|
|
610
|
+
const from =
|
|
611
|
+
fromDoor.length === 1 ? DOOR_SOURCE : `${DOOR_SOURCE} (${index + 1})`;
|
|
612
|
+
origins.push({from, key: `${from}\n${host}`, source});
|
|
613
|
+
});
|
|
589
614
|
|
|
590
615
|
/** @type {Set<unknown>} */
|
|
591
616
|
const called = new Set();
|
|
@@ -594,7 +619,7 @@ async function callOwnSources(project, request = {}, options = {}) {
|
|
|
594
619
|
const ask = request.package
|
|
595
620
|
? {package: request.package, ...(request.version ? {version: request.version} : {})}
|
|
596
621
|
: {};
|
|
597
|
-
for (const {from, source, error} of origins) {
|
|
622
|
+
for (const {from, key = from, source, error} of origins) {
|
|
598
623
|
if (source == null) {
|
|
599
624
|
result.sources.push({name: from, from, status: 'failed', error});
|
|
600
625
|
continue;
|
|
@@ -603,7 +628,7 @@ async function callOwnSources(project, request = {}, options = {}) {
|
|
|
603
628
|
called.add(source);
|
|
604
629
|
|
|
605
630
|
const label = `the discover source from ${from}`;
|
|
606
|
-
const file = savedCopyPath(cacheDir,
|
|
631
|
+
const file = savedCopyPath(cacheDir, key, ask);
|
|
607
632
|
/** @type {import('../../authoring/discover/type').DiscoverCatalog} */
|
|
608
633
|
let catalog;
|
|
609
634
|
try {
|
|
@@ -21,6 +21,10 @@ import {
|
|
|
21
21
|
withDeclaredOfficial,
|
|
22
22
|
} from './_adapter.mjs';
|
|
23
23
|
import {parseDiscoverCatalog} from '../../authoring/discover/parse.mjs';
|
|
24
|
+
import {
|
|
25
|
+
_resetHostedRun,
|
|
26
|
+
activateHostedRun,
|
|
27
|
+
} from '../../foundation/runtime/package-root.mjs';
|
|
24
28
|
|
|
25
29
|
/** No official packages, so a test sees only its own sources after it. */
|
|
26
30
|
const NO_OFFICIAL = {packages: []};
|
|
@@ -230,6 +234,44 @@ describe('callSources', () => {
|
|
|
230
234
|
expect(otherRequest.sources[0].status).toBe('failed');
|
|
231
235
|
});
|
|
232
236
|
|
|
237
|
+
it("keeps a host's saved copies per host, so one tool never answers with another's", async () => {
|
|
238
|
+
let online = true;
|
|
239
|
+
const source = async () => {
|
|
240
|
+
if (!online) throw new Error('offline');
|
|
241
|
+
return catalog('Acme catalog', [pkg('@acme/one')]);
|
|
242
|
+
};
|
|
243
|
+
const options = {cacheDir, official: NO_OFFICIAL};
|
|
244
|
+
try {
|
|
245
|
+
activateHostedRun({
|
|
246
|
+
discoverSources: [source],
|
|
247
|
+
startingRoot: '/tools/acme',
|
|
248
|
+
});
|
|
249
|
+
await callSources(undefined, {}, options);
|
|
250
|
+
online = false;
|
|
251
|
+
const sameHost = await callSources(undefined, {}, options);
|
|
252
|
+
expect(sameHost.sources[0]).toMatchObject({
|
|
253
|
+
name: 'Acme catalog',
|
|
254
|
+
from: 'the host',
|
|
255
|
+
status: 'saved',
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
_resetHostedRun();
|
|
259
|
+
activateHostedRun({
|
|
260
|
+
discoverSources: [source],
|
|
261
|
+
startingRoot: '/tools/other',
|
|
262
|
+
});
|
|
263
|
+
const otherHost = await callSources(undefined, {}, options);
|
|
264
|
+
expect(otherHost.sources[0]).toMatchObject({
|
|
265
|
+
from: 'the host',
|
|
266
|
+
status: 'failed',
|
|
267
|
+
error: 'offline',
|
|
268
|
+
});
|
|
269
|
+
expect(otherHost.packages).toEqual([]);
|
|
270
|
+
} finally {
|
|
271
|
+
_resetHostedRun();
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
233
275
|
it('keeps the saved copy in the cache directory, not in the project', async () => {
|
|
234
276
|
await callSources(
|
|
235
277
|
project({
|
package/api/docs/_adapter.d.mts
CHANGED
|
@@ -226,7 +226,7 @@ export function topicUp(entry: import("../../foundation/discovery/docs-discovery
|
|
|
226
226
|
export function placeLinks(tree: DocsTree, node: TreeNode): import("./docs.type.mjs").DocsLinks;
|
|
227
227
|
/**
|
|
228
228
|
* The moves a topic read offers: from its place in the tree, where a guide
|
|
229
|
-
* sits in its namespace and a flat topic in
|
|
229
|
+
* sits in its namespace and a flat topic in its topic level.
|
|
230
230
|
* @param {DocsCatalog} catalog
|
|
231
231
|
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
232
232
|
* @returns {Promise<import('./docs.type.mjs').DocsLinks>}
|
|
@@ -290,7 +290,7 @@ export function holdsOwnName(tree: DocsTree, catalog: DocsCatalog, entry: import
|
|
|
290
290
|
/**
|
|
291
291
|
* The doc that took a flat topic's route in the docs tree, when it is not
|
|
292
292
|
* that topic (spec:AST-046 FR11): the CLI keeps its routes, such as `cli`
|
|
293
|
-
* and `
|
|
293
|
+
* and `guides`, and a namespace keeps its route over a topic of the same
|
|
294
294
|
* name. Null when the topic owns its route, or the tree has no node there.
|
|
295
295
|
* @param {DocsTree} tree
|
|
296
296
|
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
package/api/docs/_adapter.mjs
CHANGED
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
cliDocSection,
|
|
53
53
|
} from '../../foundation/discovery/cli-self-docs.mjs';
|
|
54
54
|
import {
|
|
55
|
+
AUTHORING_REFERENCE_ROUTE,
|
|
55
56
|
loadAuthoringSelfDocs,
|
|
56
57
|
schemaFieldTable,
|
|
57
58
|
selfDocSection,
|
|
@@ -70,6 +71,7 @@ import {
|
|
|
70
71
|
import {findCoreDir} from '../../foundation/fs/paths.mjs';
|
|
71
72
|
import {AstryxError} from '../error.mjs';
|
|
72
73
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
74
|
+
import {orderRouteSuggestions} from '../../foundation/text/suggest-order.mjs';
|
|
73
75
|
import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
|
|
74
76
|
|
|
75
77
|
export {OVERLAY_LANGUAGES, overlayLanguages};
|
|
@@ -385,7 +387,7 @@ export function projectTree(catalog, {fresh = false} = {}) {
|
|
|
385
387
|
let cliTreeInputs;
|
|
386
388
|
|
|
387
389
|
/**
|
|
388
|
-
* Every flat topic in the catalog, as the tree's
|
|
390
|
+
* Every flat topic in the catalog, as the tree's topic levels read it.
|
|
389
391
|
* @param {DocsCatalog} catalog
|
|
390
392
|
* @returns {Promise<import('../../foundation/doc-compiler/tree.mjs').TreeTopicInput[]>}
|
|
391
393
|
*/
|
|
@@ -394,12 +396,13 @@ async function flatTopicInputs(catalog) {
|
|
|
394
396
|
const topics = [];
|
|
395
397
|
for (const entry of catalog.entries()) {
|
|
396
398
|
const aliases = catalog.aliasesOf(entry);
|
|
397
|
-
let {title, description} = entry;
|
|
398
|
-
if (title == null || description == null) {
|
|
399
|
+
let {title, description, category} = entry;
|
|
400
|
+
if (title == null || description == null || category === undefined) {
|
|
399
401
|
try {
|
|
400
402
|
const file = await loadTopicFile(entry.path, null);
|
|
401
403
|
title ??= file.doc?.title;
|
|
402
404
|
description ??= file.doc?.description;
|
|
405
|
+
category ??= file.doc?.category;
|
|
403
406
|
} catch {
|
|
404
407
|
// A topic that does not load is reported where it is read.
|
|
405
408
|
}
|
|
@@ -410,6 +413,7 @@ async function flatTopicInputs(catalog) {
|
|
|
410
413
|
name: entry.name,
|
|
411
414
|
title: title ?? entry.name,
|
|
412
415
|
summary: description ?? '',
|
|
416
|
+
category: category ?? null,
|
|
413
417
|
source: `${entry.package}:${entry.name}`,
|
|
414
418
|
...(aliases.length > 0 ? {aliases} : {}),
|
|
415
419
|
});
|
|
@@ -419,7 +423,7 @@ async function flatTopicInputs(catalog) {
|
|
|
419
423
|
|
|
420
424
|
/**
|
|
421
425
|
* The CLI's tree, each configured integration's namespaces and guides, and
|
|
422
|
-
* every flat topic in the generated
|
|
426
|
+
* every flat topic in the generated level for its category.
|
|
423
427
|
* @param {DocsCatalog} catalog
|
|
424
428
|
* @param {boolean} fresh
|
|
425
429
|
* @returns {Promise<DocsTree>}
|
|
@@ -509,23 +513,22 @@ function identitiesOf(tree) {
|
|
|
509
513
|
}
|
|
510
514
|
|
|
511
515
|
/**
|
|
512
|
-
* The CLI's authoring docs, by kind and name.
|
|
513
|
-
* each as one section keyed by its name, so a
|
|
514
|
-
* Loaded once per process, like the CLI's
|
|
516
|
+
* The CLI's authoring docs, by kind and name. The field reference under
|
|
517
|
+
* `astryx docs authoring` reads each as one section keyed by its name, so a
|
|
518
|
+
* link to one opens that section. Loaded once per process, like the CLI's
|
|
519
|
+
* tree files.
|
|
515
520
|
* @type {Promise<Map<string, any>> | undefined}
|
|
516
521
|
*/
|
|
517
522
|
let authoringDocs;
|
|
518
523
|
|
|
519
524
|
/**
|
|
520
|
-
* The CLI authoring doc a link names
|
|
521
|
-
*
|
|
522
|
-
* @param {DocsCatalog} catalog
|
|
525
|
+
* The CLI authoring doc a link names. The `authoring` namespace is the CLI's
|
|
526
|
+
* own, so no integration can take its route.
|
|
523
527
|
* @param {string} kind
|
|
524
528
|
* @param {string} name
|
|
525
529
|
* @returns {Promise<any | null>}
|
|
526
530
|
*/
|
|
527
|
-
async function authoringDoc(
|
|
528
|
-
if (catalog.resolve('authoring')?.package !== CLI_PROVIDER_ID) return null;
|
|
531
|
+
async function authoringDoc(kind, name) {
|
|
529
532
|
authoringDocs ??= loadAuthoringSelfDocs().then(
|
|
530
533
|
({loaded}) =>
|
|
531
534
|
new Map(loaded.map(({doc}) => [`${doc.type}\u0000${doc.name}`, doc])),
|
|
@@ -611,14 +614,14 @@ function docFinderOver(catalog, tree, fromProvider, summaries = true) {
|
|
|
611
614
|
}
|
|
612
615
|
const authored =
|
|
613
616
|
provider === CLI_PROVIDER_ID
|
|
614
|
-
? await authoringDoc(
|
|
617
|
+
? await authoringDoc(parsed.kind, parsed.name)
|
|
615
618
|
: null;
|
|
616
619
|
if (authored) {
|
|
617
620
|
return {
|
|
618
621
|
link: {
|
|
619
622
|
target,
|
|
620
623
|
id: createDocId(provider, authored.type, authored.name),
|
|
621
|
-
route:
|
|
624
|
+
route: AUTHORING_REFERENCE_ROUTE,
|
|
622
625
|
title: authored.displayName ?? authored.name,
|
|
623
626
|
summary: authored.description ?? '',
|
|
624
627
|
command: `astryx docs authoring ${authored.name}`,
|
|
@@ -1146,6 +1149,14 @@ function packageCatalog(integration, discovered) {
|
|
|
1146
1149
|
* @returns {Promise<Array<{severity: 'warning', message: string}>>}
|
|
1147
1150
|
*/
|
|
1148
1151
|
export async function packageComponentLinkProblems(integration, discovered) {
|
|
1152
|
+
// A package with no provider id (its manifest's, else its name) links
|
|
1153
|
+
// nothing, as on the read path: its text reads as written, so there is
|
|
1154
|
+
// nothing to report.
|
|
1155
|
+
try {
|
|
1156
|
+
normalizeProviderId(integration.providerId ?? integration.name);
|
|
1157
|
+
} catch {
|
|
1158
|
+
return [];
|
|
1159
|
+
}
|
|
1149
1160
|
const catalog = packageCatalog(integration, discovered);
|
|
1150
1161
|
return (await componentLinkProblems(catalog, integration.name)).map(
|
|
1151
1162
|
message => ({severity: /** @type {const} */ ('warning'), message}),
|
|
@@ -1176,11 +1187,15 @@ async function componentLinkProblems(catalog, owner) {
|
|
|
1176
1187
|
// The components check reports a doc that does not load.
|
|
1177
1188
|
continue;
|
|
1178
1189
|
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
componentLinkProvider(record.package, record.providerId)
|
|
1182
|
-
|
|
1183
|
-
|
|
1190
|
+
let provider;
|
|
1191
|
+
try {
|
|
1192
|
+
provider = componentLinkProvider(record.package, record.providerId);
|
|
1193
|
+
} catch {
|
|
1194
|
+
// An owner that is not a provider id links nothing (as on the read
|
|
1195
|
+
// path); its text reads as written.
|
|
1196
|
+
continue;
|
|
1197
|
+
}
|
|
1198
|
+
const linked = await linkComponentDoc(catalog, provider, doc);
|
|
1184
1199
|
const name = typeof doc?.name === 'string' ? doc.name : record.name;
|
|
1185
1200
|
for (const problem of linked.problems) {
|
|
1186
1201
|
problems.push(
|
|
@@ -1416,7 +1431,7 @@ export function placeLinks(tree, node) {
|
|
|
1416
1431
|
|
|
1417
1432
|
/**
|
|
1418
1433
|
* The moves a topic read offers: from its place in the tree, where a guide
|
|
1419
|
-
* sits in its namespace and a flat topic in
|
|
1434
|
+
* sits in its namespace and a flat topic in its topic level.
|
|
1420
1435
|
* @param {DocsCatalog} catalog
|
|
1421
1436
|
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
1422
1437
|
* @returns {Promise<import('./docs.type.mjs').DocsLinks>}
|
|
@@ -1514,7 +1529,7 @@ function treeArgument(catalog, tree, node) {
|
|
|
1514
1529
|
/**
|
|
1515
1530
|
* The doc that took a flat topic's route in the docs tree, when it is not
|
|
1516
1531
|
* that topic (spec:AST-046 FR11): the CLI keeps its routes, such as `cli`
|
|
1517
|
-
* and `
|
|
1532
|
+
* and `guides`, and a namespace keeps its route over a topic of the same
|
|
1518
1533
|
* name. Null when the topic owns its route, or the tree has no node there.
|
|
1519
1534
|
* @param {DocsTree} tree
|
|
1520
1535
|
* @param {import('../../foundation/discovery/docs-discovery.mjs').DocsTopicEntry} entry
|
|
@@ -1528,6 +1543,35 @@ export function routeOwner(tree, entry) {
|
|
|
1528
1543
|
: node;
|
|
1529
1544
|
}
|
|
1530
1545
|
|
|
1546
|
+
/**
|
|
1547
|
+
* Routes that moved, old prefix first: the integration guides moved from
|
|
1548
|
+
* `cli/integrations` (and, before that, the `cli-integrations` topic) into
|
|
1549
|
+
* `authoring`, the one home for integration authors.
|
|
1550
|
+
* Only the not-found error reads this, to name where a doc went; an old route
|
|
1551
|
+
* opens nothing.
|
|
1552
|
+
*/
|
|
1553
|
+
const MOVED_ROUTES = [
|
|
1554
|
+
['cli/integrations', 'authoring'],
|
|
1555
|
+
['cli-integrations', 'authoring'],
|
|
1556
|
+
];
|
|
1557
|
+
|
|
1558
|
+
/**
|
|
1559
|
+
* The node an old route moved to, or null.
|
|
1560
|
+
* @param {unknown} topic
|
|
1561
|
+
* @param {DocsTree} tree
|
|
1562
|
+
* @returns {TreeNode | null}
|
|
1563
|
+
*/
|
|
1564
|
+
function movedRoute(topic, tree) {
|
|
1565
|
+
if (typeof topic !== 'string') return null;
|
|
1566
|
+
const wanted = topic.toLowerCase();
|
|
1567
|
+
for (const [from, to] of MOVED_ROUTES) {
|
|
1568
|
+
if (wanted !== from && !wanted.startsWith(`${from}/`)) continue;
|
|
1569
|
+
const node = tree.getFolded(`${to}${wanted.slice(from.length)}`);
|
|
1570
|
+
if (node) return node;
|
|
1571
|
+
}
|
|
1572
|
+
return null;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1531
1575
|
/**
|
|
1532
1576
|
* The error for a docs argument that names nothing. For a route, it suggests
|
|
1533
1577
|
* the children of the deepest namespace the route reaches; otherwise, every
|
|
@@ -1560,8 +1604,7 @@ export async function unknownTopicError(topic, catalog) {
|
|
|
1560
1604
|
}
|
|
1561
1605
|
if (suggestions.length === 0 && typeof topic === 'string') {
|
|
1562
1606
|
// The docs whose own name it is (`doctor` is cli/commands/doctor), or whose
|
|
1563
|
-
// route it spells with hyphens (`cli-
|
|
1564
|
-
// it moved to cli/integrations).
|
|
1607
|
+
// route it spells with hyphens (`cli-host-entry` is cli/host-entry).
|
|
1565
1608
|
const wanted = topic.toLowerCase();
|
|
1566
1609
|
suggestions = [...tree.nodes.values()]
|
|
1567
1610
|
.filter(
|
|
@@ -1580,6 +1623,22 @@ export async function unknownTopicError(topic, catalog) {
|
|
|
1580
1623
|
...catalog.names().map(name => ({name, reason: 'available topic'})),
|
|
1581
1624
|
];
|
|
1582
1625
|
}
|
|
1626
|
+
if (typeof topic === 'string') {
|
|
1627
|
+
suggestions = orderRouteSuggestions(topic, suggestions);
|
|
1628
|
+
}
|
|
1629
|
+
// A route that moved names where it went, ahead of the usual suggestions
|
|
1630
|
+
// (spec:AST-046 FR9, FR6).
|
|
1631
|
+
const moved = movedRoute(topic, tree);
|
|
1632
|
+
if (moved) {
|
|
1633
|
+
return new AstryxError(
|
|
1634
|
+
`Unknown topic "${String(topic)}". It moved to "${moved.route}"${notLoaded(catalog)}`,
|
|
1635
|
+
[
|
|
1636
|
+
{name: moved.route, reason: moved.summary},
|
|
1637
|
+
...suggestions.filter(entry => entry.name !== moved.route),
|
|
1638
|
+
],
|
|
1639
|
+
ERROR_CODES.ERR_UNKNOWN_TOPIC,
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1583
1642
|
return new AstryxError(
|
|
1584
1643
|
`Unknown topic "${String(topic)}"${notLoaded(catalog)}`,
|
|
1585
1644
|
suggestions,
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Every Core doc has a named home in the docs tree (spec:AST-046 FR12).
|
|
5
|
+
*
|
|
6
|
+
* A reader sees a doc's home in its path (`Guides › Getting started`) and in
|
|
7
|
+
* its Up move. A flat Core topic sits in Guides or Foundations by the
|
|
8
|
+
* category it declares, so a new topic with no category, or one the levels
|
|
9
|
+
* do not know, fails here instead of landing in a catch-all. The integration
|
|
10
|
+
* guides and their field reference live under `authoring`, and the routes
|
|
11
|
+
* they left name where they went.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {describe, expect, it} from 'vitest';
|
|
15
|
+
import {docs} from './docs.mjs';
|
|
16
|
+
import {TOPIC_LEVELS} from '../../foundation/doc-compiler/tree.mjs';
|
|
17
|
+
|
|
18
|
+
const CLI = '@astryxdesign/cli';
|
|
19
|
+
const SLOW = 60_000;
|
|
20
|
+
|
|
21
|
+
describe('every Core doc has a named home', () => {
|
|
22
|
+
it(
|
|
23
|
+
'puts each flat Core topic in Guides or Foundations by its category',
|
|
24
|
+
async () => {
|
|
25
|
+
const list = await docs();
|
|
26
|
+
const core = list.data.filter(topic => topic.package === CLI);
|
|
27
|
+
expect(core.length).toBeGreaterThan(10);
|
|
28
|
+
/** @type {string[]} */
|
|
29
|
+
const unfiled = [];
|
|
30
|
+
for (const topic of core) {
|
|
31
|
+
const read = await docs(topic.topic);
|
|
32
|
+
const {category} = read.data;
|
|
33
|
+
if (category !== 'guide' && category !== 'foundations') {
|
|
34
|
+
unfiled.push(`${topic.topic} (category ${String(category)})`);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const level =
|
|
38
|
+
category === 'foundations'
|
|
39
|
+
? TOPIC_LEVELS.foundations
|
|
40
|
+
: TOPIC_LEVELS.guides;
|
|
41
|
+
expect(read.data.links.up, topic.topic).toBe(
|
|
42
|
+
`astryx docs ${level.route}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
expect(unfiled, 'Core topics with no home: give each a category').toEqual(
|
|
46
|
+
[],
|
|
47
|
+
);
|
|
48
|
+
},
|
|
49
|
+
SLOW,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
it(
|
|
53
|
+
'lists each level under a plain name, and no catch-all',
|
|
54
|
+
async () => {
|
|
55
|
+
const list = await docs();
|
|
56
|
+
const roots = (list.meta.namespaces ?? []).map(entry => entry.topic);
|
|
57
|
+
expect(roots).toEqual(expect.arrayContaining(['guides', 'foundations']));
|
|
58
|
+
expect(roots).not.toContain('unorganized');
|
|
59
|
+
const guides = await docs('guides');
|
|
60
|
+
expect(guides.data).toMatchObject({route: 'guides', title: 'Guides'});
|
|
61
|
+
expect(guides.data.slots[0].children.map(child => child.route)).toEqual(
|
|
62
|
+
expect.arrayContaining(['getting-started', 'principles', 'theme']),
|
|
63
|
+
);
|
|
64
|
+
const foundations = await docs('foundations');
|
|
65
|
+
expect(foundations.data.title).toBe('Foundations');
|
|
66
|
+
expect(
|
|
67
|
+
foundations.data.slots[0].children.map(child => child.route),
|
|
68
|
+
).toEqual(expect.arrayContaining(['color', 'icons', 'spacing']));
|
|
69
|
+
await expect(docs('unorganized')).rejects.toMatchObject({
|
|
70
|
+
code: 'ERR_UNKNOWN_TOPIC',
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
SLOW,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
it(
|
|
77
|
+
'keeps everything for integration authors under authoring, and names where an old route went',
|
|
78
|
+
async () => {
|
|
79
|
+
const authoring = await docs('authoring');
|
|
80
|
+
expect(authoring.data).toMatchObject({
|
|
81
|
+
route: 'authoring',
|
|
82
|
+
kind: 'namespace',
|
|
83
|
+
breadcrumb: [],
|
|
84
|
+
links: {up: 'astryx docs'},
|
|
85
|
+
});
|
|
86
|
+
const children = authoring.data.slots.flatMap(slot =>
|
|
87
|
+
slot.children.map(child => child.route),
|
|
88
|
+
);
|
|
89
|
+
expect(children).toEqual(
|
|
90
|
+
expect.arrayContaining([
|
|
91
|
+
'authoring/quick-start',
|
|
92
|
+
'authoring/building-blocks',
|
|
93
|
+
'authoring/ship',
|
|
94
|
+
'authoring/help',
|
|
95
|
+
'authoring/field-reference',
|
|
96
|
+
]),
|
|
97
|
+
);
|
|
98
|
+
// Every field reference section still opens from the namespace by its
|
|
99
|
+
// key, as `astryx docs authoring <name>` did on the topic (FR13).
|
|
100
|
+
const reference = await docs('authoring/field-reference', undefined, {
|
|
101
|
+
index: true,
|
|
102
|
+
});
|
|
103
|
+
const keys = reference.data.sections.map(section => section.id);
|
|
104
|
+
expect(keys.length).toBeGreaterThan(15);
|
|
105
|
+
for (const key of keys) {
|
|
106
|
+
const section = await docs('authoring', key);
|
|
107
|
+
expect(section.type, key).toBe('docs.detail.section');
|
|
108
|
+
expect(section.data.id, key).toBe(key);
|
|
109
|
+
}
|
|
110
|
+
for (const [old, now] of [
|
|
111
|
+
['cli/integrations', 'authoring'],
|
|
112
|
+
['cli/integrations/quick-start', 'authoring/quick-start'],
|
|
113
|
+
['cli/integrations/ship/publishing', 'authoring/ship/publishing'],
|
|
114
|
+
]) {
|
|
115
|
+
const error = await docs(old).catch(e => e);
|
|
116
|
+
expect(error).toMatchObject({
|
|
117
|
+
code: 'ERR_UNKNOWN_TOPIC',
|
|
118
|
+
message: expect.stringContaining(`It moved to "${now}"`),
|
|
119
|
+
});
|
|
120
|
+
// The new route comes first, ahead of the suggestions any unknown
|
|
121
|
+
// route gets (FR6).
|
|
122
|
+
expect(error.suggestions[0]).toMatchObject({name: now});
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
SLOW,
|
|
126
|
+
);
|
|
127
|
+
});
|
package/api/docs/docs.doc.mjs
CHANGED
|
@@ -28,7 +28,7 @@ export const doc = {
|
|
|
28
28
|
'`cli/api` returns its children one level down (`depth` reads as many ' +
|
|
29
29
|
'levels as asked, and `detail` how much of each doc below), a typed doc such as ' +
|
|
30
30
|
"`cli/api/functions/search` returns its content, and a guide the tree " +
|
|
31
|
-
'places (`
|
|
31
|
+
'places (`authoring/quick-start`) reads like any topic. ' +
|
|
32
32
|
'Every read but the list carries `links`, the commands that move from it: ' +
|
|
33
33
|
'`up` to the level it sits in, `previous` and `next` to its neighbors, and, ' +
|
|
34
34
|
'for a typed doc, `related` to the docs it names (its command or function, ' +
|
|
@@ -162,12 +162,12 @@ export const doc = {
|
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
164
|
label: 'A namespace and everything below it, in full',
|
|
165
|
-
code: "await docs('
|
|
165
|
+
code: "await docs('authoring', undefined, {depth: 'all', detail: 'full'});",
|
|
166
166
|
},
|
|
167
167
|
{label: 'One API function', code: "await docs('cli/api/functions/search');"},
|
|
168
168
|
{
|
|
169
169
|
label: 'A whole guide from the docs tree',
|
|
170
|
-
code: "await docs('
|
|
170
|
+
code: "await docs('authoring/quick-start');",
|
|
171
171
|
},
|
|
172
172
|
{label: 'One section by key', code: "await docs('spacing', 'scale');"},
|
|
173
173
|
],
|