@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
|
@@ -22,6 +22,7 @@ import * as path from 'node:path';
|
|
|
22
22
|
import {lowerDoc} from '../doc-compiler/compile.mjs';
|
|
23
23
|
import {packageSource} from '../doc-compiler/source.mjs';
|
|
24
24
|
import {CLI_ROOT} from '../fs/paths.mjs';
|
|
25
|
+
import {formatCliCommand} from '../env/package-manager.mjs';
|
|
25
26
|
import {LOCAL_THEME_ROOT} from '../config/theme-state.mjs';
|
|
26
27
|
import {assertWithin, PathSafetyError} from '../fs/path-safety.mjs';
|
|
27
28
|
|
|
@@ -958,6 +959,126 @@ function declaresThemeDoc(ast, exportDefault) {
|
|
|
958
959
|
});
|
|
959
960
|
}
|
|
960
961
|
|
|
962
|
+
/**
|
|
963
|
+
* Whether a file is the module `astryx theme build` writes rather than a
|
|
964
|
+
* theme source: plain JavaScript that carries the build's generated header
|
|
965
|
+
* and never calls defineTheme.
|
|
966
|
+
* @param {string} file
|
|
967
|
+
*/
|
|
968
|
+
function isBuiltThemeModule(file) {
|
|
969
|
+
if (!/\.m?js$/u.test(file)) return false;
|
|
970
|
+
let text;
|
|
971
|
+
try {
|
|
972
|
+
text = fs.readFileSync(file, 'utf8');
|
|
973
|
+
} catch {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
return (
|
|
977
|
+
/@generated by `astryx theme build`/u.test(text) &&
|
|
978
|
+
!/\bdefineTheme\b/u.test(text)
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* The fix when a descriptor's stem names both a theme source and the module
|
|
984
|
+
* `astryx theme build` writes beside it (`brand.ts` and its built `brand.js`):
|
|
985
|
+
* the build names its output after the theme, so the source and descriptor
|
|
986
|
+
* take the `<name>Theme` stem instead. Null when no built module is among
|
|
987
|
+
* the matches, or the stem already ends in `Theme`.
|
|
988
|
+
* @param {string} sourceDir
|
|
989
|
+
* @param {string[]} sources same-stem module file names
|
|
990
|
+
* @param {string} doc the descriptor's file name
|
|
991
|
+
* @param {string} exportName the descriptor's stem
|
|
992
|
+
* @returns {string | null}
|
|
993
|
+
*/
|
|
994
|
+
function builtThemeSourceFix(sourceDir, sources, doc, exportName) {
|
|
995
|
+
if (exportName.endsWith('Theme')) return null;
|
|
996
|
+
const built = sources.filter(file =>
|
|
997
|
+
isBuiltThemeModule(path.join(sourceDir, file)),
|
|
998
|
+
);
|
|
999
|
+
const source = sources.filter(file => !built.includes(file));
|
|
1000
|
+
if (built.length === 0 || source.length !== 1) return null;
|
|
1001
|
+
const extension = source[0].slice(exportName.length);
|
|
1002
|
+
const stem = `${exportName}Theme`;
|
|
1003
|
+
return `Fix: ${built.map(file => `"${file}"`).join(', ')} is the module \`${formatCliCommand('theme build', sourceDir)}\` writes, which takes the theme's name; rename ${source[0]} to ${stem}${extension} and ${doc} to ${stem}${THEME_DOC_SUFFIX}, export \`${stem}\` from it, and build again.`;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Why a descriptor pairs with the built module and the built module lacks
|
|
1008
|
+
* the export the descriptor's stem names (`ocean.doc.mjs` beside a built
|
|
1009
|
+
* `ocean.js` that exports `oceanTheme`): the descriptor is named for the
|
|
1010
|
+
* build's output, not the theme's source. The source is named only when the
|
|
1011
|
+
* built module's `Source:` header, or a source whose defineTheme gives the
|
|
1012
|
+
* theme's name, confirms it; otherwise the message stays generic. Null when
|
|
1013
|
+
* the entry is not a built module.
|
|
1014
|
+
* @param {string} label the descriptor, as messages name it
|
|
1015
|
+
* @param {string} sourceDir
|
|
1016
|
+
* @param {string} entry the file the descriptor pairs with
|
|
1017
|
+
* @param {string} exportName the descriptor's stem
|
|
1018
|
+
* @param {string} doc the descriptor's file name
|
|
1019
|
+
* @param {string} slug the theme's name
|
|
1020
|
+
* @param {string[]} files the theme folder's files
|
|
1021
|
+
* @returns {string | null}
|
|
1022
|
+
*/
|
|
1023
|
+
function builtModuleDescriptorMessage(
|
|
1024
|
+
label,
|
|
1025
|
+
sourceDir,
|
|
1026
|
+
entry,
|
|
1027
|
+
exportName,
|
|
1028
|
+
doc,
|
|
1029
|
+
slug,
|
|
1030
|
+
files,
|
|
1031
|
+
) {
|
|
1032
|
+
if (!isBuiltThemeModule(path.join(sourceDir, entry))) return null;
|
|
1033
|
+
const source = confirmedThemeSource(sourceDir, entry, slug, files);
|
|
1034
|
+
const head = `${label} shares its stem with the built module "${entry}", which does not export "${exportName}": a descriptor must share its stem with the source that calls defineTheme.`;
|
|
1035
|
+
if (source == null) {
|
|
1036
|
+
return `${head} Fix: rename ${doc} to share its stem with the theme's source (the module that calls defineTheme, such as ${exportName}Theme.ts).`;
|
|
1037
|
+
}
|
|
1038
|
+
const stem = source.replace(/\.[^.]+$/u, '');
|
|
1039
|
+
return `${head} The theme's source is "${source}". Fix: rename ${doc} to ${stem}${THEME_DOC_SUFFIX}.`;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* The theme's source, when something confirms it: the file the built
|
|
1044
|
+
* module's `Source:` header names, if it is in the folder, else the one
|
|
1045
|
+
* module in the folder whose defineTheme gives the theme's name as a
|
|
1046
|
+
* literal. Null otherwise: a `<name>Theme` file alone may be a helper.
|
|
1047
|
+
* @param {string} sourceDir
|
|
1048
|
+
* @param {string} built the built module's file name
|
|
1049
|
+
* @param {string} slug
|
|
1050
|
+
* @param {string[]} files
|
|
1051
|
+
* @returns {string | null}
|
|
1052
|
+
*/
|
|
1053
|
+
function confirmedThemeSource(sourceDir, built, slug, files) {
|
|
1054
|
+
const own = files.filter(
|
|
1055
|
+
file =>
|
|
1056
|
+
!file.includes('/') &&
|
|
1057
|
+
file !== built &&
|
|
1058
|
+
THEME_MODULE_EXTENSIONS.some(extension => file.endsWith(extension)),
|
|
1059
|
+
);
|
|
1060
|
+
/** @param {string} file */
|
|
1061
|
+
const read = file => {
|
|
1062
|
+
try {
|
|
1063
|
+
return fs.readFileSync(path.join(sourceDir, file), 'utf8');
|
|
1064
|
+
} catch {
|
|
1065
|
+
return '';
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
const header = /^\s*\*?\s*Source:\s*(\S+)\s*$/mu.exec(read(built));
|
|
1069
|
+
if (header) {
|
|
1070
|
+
const named = path.posix.basename(header[1].replace(/\\/gu, '/'));
|
|
1071
|
+
if (own.includes(named)) return named;
|
|
1072
|
+
}
|
|
1073
|
+
const quoted = slug.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
1074
|
+
const naming = new RegExp(
|
|
1075
|
+
`\\bdefineTheme\\s*\\(\\s*\\{[^}]*\\bname\\s*:\\s*['"\`]${quoted}['"\`]`,
|
|
1076
|
+
'u',
|
|
1077
|
+
);
|
|
1078
|
+
const matches = own.filter(file => naming.test(read(file)));
|
|
1079
|
+
return matches.length === 1 ? matches[0] : null;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
961
1082
|
/** A module named for the theme it exports, such as `oceanTheme.ts`. */
|
|
962
1083
|
const THEME_SOURCE_RE = /^[$A-Z_a-z][$\w]*Theme\.(?:mjs|js|mts|ts|tsx|jsx)$/u;
|
|
963
1084
|
|
|
@@ -1240,8 +1361,17 @@ export function discoverThemeDirectory(
|
|
|
1240
1361
|
: evidence.includes('/')
|
|
1241
1362
|
? `; "${evidence}" is in a subfolder`
|
|
1242
1363
|
: ` beside "${evidence}"`;
|
|
1364
|
+
const themeDoc = formatCliCommand('docs authoring theme-doc', sourceDir);
|
|
1365
|
+
const fix =
|
|
1366
|
+
docs.length > 1
|
|
1367
|
+
? `Fix: keep the one descriptor that shares its stem with the theme's source and delete the rest.`
|
|
1368
|
+
: evidence.includes('/')
|
|
1369
|
+
? `Fix: move "${evidence}" up into ${slug}/, beside where its descriptor goes.`
|
|
1370
|
+
: THEME_SOURCE_RE.test(evidence)
|
|
1371
|
+
? `Fix: add ${evidence.replace(/\.[^.]+$/u, '')}${THEME_DOC_SUFFIX} beside it with type: 'theme' and name: '${slug}'; \`${themeDoc}\` lists its fields.`
|
|
1372
|
+
: `Fix: add a descriptor that shares its stem with the theme's source, with type: 'theme' and name: '${slug}'; \`${themeDoc}\` lists its fields.`;
|
|
1243
1373
|
throw new Error(
|
|
1244
|
-
`${theme} must contain exactly one same-stem .doc.mjs descriptor; found ${docs.length}${detail}
|
|
1374
|
+
`${theme} must contain exactly one same-stem .doc.mjs descriptor; found ${docs.length}${detail}. ${fix}`,
|
|
1245
1375
|
);
|
|
1246
1376
|
}
|
|
1247
1377
|
const nested = descriptors.find(file => file.includes('/'));
|
|
@@ -1267,8 +1397,13 @@ export function discoverThemeDirectory(
|
|
|
1267
1397
|
extension => `${exportName}${extension}`,
|
|
1268
1398
|
).filter(file => listing.files.includes(file));
|
|
1269
1399
|
if (sources.length !== 1) {
|
|
1400
|
+
const fix =
|
|
1401
|
+
sources.length > 1
|
|
1402
|
+
? (builtThemeSourceFix(sourceDir, sources, docs[0], exportName) ??
|
|
1403
|
+
`Fix: keep one of them; the theme's source is a single module.`)
|
|
1404
|
+
: `Fix: add ${exportName}.ts beside ${docs[0]}, exporting \`${exportName}\` from defineTheme.`;
|
|
1270
1405
|
throw new Error(
|
|
1271
|
-
`${theme} must contain exactly one same-stem source for ${docs[0]}; found ${sources.length}${sources.length > 1 ? `: ${quoted(sources)}` : ''}
|
|
1406
|
+
`${theme} must contain exactly one same-stem source for ${docs[0]}; found ${sources.length}${sources.length > 1 ? `: ${quoted(sources)}` : ''}. ${fix}`,
|
|
1272
1407
|
);
|
|
1273
1408
|
}
|
|
1274
1409
|
|
|
@@ -1314,7 +1449,16 @@ export function discoverThemeDirectory(
|
|
|
1314
1449
|
)
|
|
1315
1450
|
) {
|
|
1316
1451
|
throw new ThemeRuntimeExportError(
|
|
1317
|
-
|
|
1452
|
+
builtModuleDescriptorMessage(
|
|
1453
|
+
label,
|
|
1454
|
+
sourceDir,
|
|
1455
|
+
entry,
|
|
1456
|
+
exportName,
|
|
1457
|
+
docs[0],
|
|
1458
|
+
slug,
|
|
1459
|
+
listing.files,
|
|
1460
|
+
) ??
|
|
1461
|
+
`Theme "${slug}" for ${owner} entry "${entry}" does not export "${exportName}".`,
|
|
1318
1462
|
);
|
|
1319
1463
|
}
|
|
1320
1464
|
} catch (error) {
|
|
@@ -102,7 +102,15 @@ const RUNNERS = {
|
|
|
102
102
|
runs: SELF_DOCS,
|
|
103
103
|
sites: ['import ../../../api/blog/blog.doc.mjs', 'import ./blog.doc.mjs'],
|
|
104
104
|
},
|
|
105
|
-
'clients/cli/commands/
|
|
105
|
+
'clients/cli/commands/manifest.mjs': {
|
|
106
|
+
runs: SELF_DOCS,
|
|
107
|
+
sites: ['import ./manifest.doc.mjs'],
|
|
108
|
+
},
|
|
109
|
+
'clients/cli/commands/postinstall.mjs': {
|
|
110
|
+
runs: SELF_DOCS,
|
|
111
|
+
sites: ['import ./postinstall.doc.mjs'],
|
|
112
|
+
},
|
|
113
|
+
'clients/cli/commands/theme.mjs': {
|
|
106
114
|
runs: `${SELF_DOCS}; and \`astryx theme build\`, a child process per theme`,
|
|
107
115
|
sites: [
|
|
108
116
|
'child_process.spawn',
|
|
@@ -135,11 +143,11 @@ const RUNNERS = {
|
|
|
135
143
|
'import ./build.doc.mjs',
|
|
136
144
|
],
|
|
137
145
|
},
|
|
138
|
-
'clients/cli/commands/component
|
|
146
|
+
'clients/cli/commands/component.mjs': {
|
|
139
147
|
runs: SELF_DOCS,
|
|
140
148
|
sites: [
|
|
141
|
-
'import
|
|
142
|
-
'import
|
|
149
|
+
'import ../../../api/component/component.doc.mjs',
|
|
150
|
+
'import ./component.doc.mjs',
|
|
143
151
|
],
|
|
144
152
|
},
|
|
145
153
|
'clients/cli/commands/discover.mjs': {
|
|
@@ -180,11 +188,11 @@ const RUNNERS = {
|
|
|
180
188
|
'import ./gap-report.doc.mjs',
|
|
181
189
|
],
|
|
182
190
|
},
|
|
183
|
-
'clients/cli/commands/hook
|
|
191
|
+
'clients/cli/commands/hook.mjs': {
|
|
184
192
|
runs: SELF_DOCS,
|
|
185
193
|
sites: [
|
|
186
|
-
'import
|
|
187
|
-
'import
|
|
194
|
+
'import ../../../api/hook/hook.doc.mjs',
|
|
195
|
+
'import ./hook.doc.mjs',
|
|
188
196
|
],
|
|
189
197
|
},
|
|
190
198
|
'clients/cli/commands/init.mjs': {
|
|
@@ -233,8 +241,8 @@ const RUNNERS = {
|
|
|
233
241
|
],
|
|
234
242
|
},
|
|
235
243
|
'clients/cli/index.mjs': {
|
|
236
|
-
runs: 'the command modules, to register each command
|
|
237
|
-
sites: ['import
|
|
244
|
+
runs: 'the command modules, to register each command',
|
|
245
|
+
sites: ['import(<computed>)'],
|
|
238
246
|
},
|
|
239
247
|
'clients/cli/lib/manifest.mjs': {
|
|
240
248
|
runs: 'the manifest command doc, for the exit codes the manifest reports',
|
|
@@ -248,6 +256,10 @@ const RUNNERS = {
|
|
|
248
256
|
runs: 'astryx.config, through the config parser',
|
|
249
257
|
sites: ['loadModuleWithParser(..., parseConfig)'],
|
|
250
258
|
},
|
|
259
|
+
'foundation/agent-docs/agent-docs.mjs': {
|
|
260
|
+
runs: 'git, sl or hg, to read whether the repository ignores an untracked agent file',
|
|
261
|
+
sites: ['child_process.spawnSync'],
|
|
262
|
+
},
|
|
251
263
|
'foundation/fs/file-protection.mjs': {
|
|
252
264
|
runs: 'the ignore matcher (CommonJS), loaded when a resolver first reads an ignore file',
|
|
253
265
|
sites: ['require(ignore)'],
|
|
@@ -272,6 +284,10 @@ const RUNNERS = {
|
|
|
272
284
|
runs: 'a contributed topic, for its catalog fields: name, title, description, category, and relationships',
|
|
273
285
|
sites: ['importDocModule'],
|
|
274
286
|
},
|
|
287
|
+
'foundation/discovery/runner-commands.mjs': {
|
|
288
|
+
runs: "the package's topics, to find each Astryx command written with a package runner",
|
|
289
|
+
sites: ['loadTopicModule'],
|
|
290
|
+
},
|
|
275
291
|
'foundation/discovery/stray-pointers.mjs': {
|
|
276
292
|
runs: "the CLI's own guides, for their names, to tell which written `astryx docs <name>` points at a doc that exists",
|
|
277
293
|
sites: ['builtinGuideFiles'],
|
|
@@ -315,6 +331,10 @@ const RUNNERS = {
|
|
|
315
331
|
'require.cache',
|
|
316
332
|
],
|
|
317
333
|
},
|
|
334
|
+
'foundation/fs/read-record.mjs': {
|
|
335
|
+
runs: "nothing; it wraps node:fs's read calls to record the paths an operation reads, and republishes them to ESM imports",
|
|
336
|
+
sites: ['module.syncBuiltinESMExports'],
|
|
337
|
+
},
|
|
318
338
|
'foundation/fs/paths.mjs': {
|
|
319
339
|
runs: "Yarn's pnpapi, under Plug'n'Play, to find an installed package",
|
|
320
340
|
sites: ['require(pnpapi)'],
|
|
@@ -339,6 +359,10 @@ const RUNNERS = {
|
|
|
339
359
|
runs: "the CLI release that answers a project's run, when it is not this copy",
|
|
340
360
|
sites: ['child_process.spawn'],
|
|
341
361
|
},
|
|
362
|
+
'host/index.mjs': {
|
|
363
|
+
runs: "another release's host entry, from one of the host's package sets, when that release answers a hosted run",
|
|
364
|
+
sites: ['import(<computed>)'],
|
|
365
|
+
},
|
|
342
366
|
'scripts/generate-cli-readme.mjs': {
|
|
343
367
|
runs: '`astryx manifest` and the error-code and response-type docs, to write the README tables (build time, not shipped)',
|
|
344
368
|
sites: ['child_process.spawnSync', 'import(<computed>)'],
|
|
@@ -173,8 +173,23 @@ export async function readDocView(file, options) {
|
|
|
173
173
|
);
|
|
174
174
|
if (result.loadFailed) throw result.loadFailure;
|
|
175
175
|
if (result.missing) {
|
|
176
|
-
if (strict)
|
|
176
|
+
if (strict) {
|
|
177
|
+
// A doc that exports nothing its reader takes (an empty file, or one
|
|
178
|
+
// with other exports) is said plainly, with what it does export and
|
|
179
|
+
// the fix; the schema would only say "(root): Invalid input".
|
|
180
|
+
const exported =
|
|
181
|
+
options.exports ??
|
|
182
|
+
/** @type {Record<string, readonly string[]>} */ (DOC_EXPORTS)[
|
|
183
|
+
options.root
|
|
184
|
+
] ??
|
|
185
|
+
[];
|
|
186
|
+
const problem =
|
|
187
|
+
result.missingValue === undefined
|
|
188
|
+
? await missingDocProblem(file, options, exported)
|
|
189
|
+
: null;
|
|
190
|
+
if (problem) throw new Error(`${options.label ?? file} ${problem}`);
|
|
177
191
|
parserFor(options.root)(result.missingValue, options.label ?? file);
|
|
192
|
+
}
|
|
178
193
|
return result.missingValue;
|
|
179
194
|
}
|
|
180
195
|
if (strict && result.failed) throw result.failure;
|
|
@@ -182,6 +197,49 @@ export async function readDocView(file, options) {
|
|
|
182
197
|
return result.view;
|
|
183
198
|
}
|
|
184
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Why a doc file exports no doc, with the fix: it is empty, or it exports
|
|
202
|
+
* other names than the ones its reader takes. Null when neither explains it.
|
|
203
|
+
* @param {string} file
|
|
204
|
+
* @param {ReadOptions} options
|
|
205
|
+
* @param {readonly string[]} exported the export names the reader takes
|
|
206
|
+
* @returns {Promise<string | null>}
|
|
207
|
+
*/
|
|
208
|
+
async function missingDocProblem(file, options, exported) {
|
|
209
|
+
// A theme descriptor is read statically, never imported.
|
|
210
|
+
if (options.root === 'themes') return null;
|
|
211
|
+
const fix =
|
|
212
|
+
'Fix: export the doc object as the default export: `export default {type: ..., name: ..., ...}`.';
|
|
213
|
+
let text;
|
|
214
|
+
try {
|
|
215
|
+
text = fs.readFileSync(file, 'utf8');
|
|
216
|
+
} catch {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const code = text
|
|
220
|
+
.replace(/^\uFEFF/u, '')
|
|
221
|
+
.replace(/\/\*[\s\S]*?\*\//gu, '')
|
|
222
|
+
.replace(/(^|[^:])\/\/.*$/gmu, '$1')
|
|
223
|
+
.trim();
|
|
224
|
+
if (code === '') return `is empty, so it documents nothing. ${fix}`;
|
|
225
|
+
/** @type {string[]} */
|
|
226
|
+
let names;
|
|
227
|
+
try {
|
|
228
|
+
const mod = await LOADERS[options.loader ?? 'user'](file);
|
|
229
|
+
names = Object.keys(mod ?? {}).filter(name => name !== 'default');
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
const takes = exported.map(name =>
|
|
234
|
+
name === 'default' ? 'default export' : `\`${name}\` export`,
|
|
235
|
+
);
|
|
236
|
+
const found =
|
|
237
|
+
names.length > 0
|
|
238
|
+
? ` (it exports ${names.map(name => `\`${name}\``).join(', ')})`
|
|
239
|
+
: ' (it exports nothing)';
|
|
240
|
+
return `has no ${takes.join(' or ')}${found}, so it documents nothing. ${fix}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
185
243
|
/**
|
|
186
244
|
* Load one file as its root reads it: the doc its module exports and, for a
|
|
187
245
|
* component or hook, the translation it exports for `lang`.
|
|
@@ -109,10 +109,19 @@ describe('readDocView', () => {
|
|
|
109
109
|
}
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
it(
|
|
112
|
+
it('reads a file with no doc as undefined, or, checked, says what it exports instead', async () => {
|
|
113
113
|
const file = write('Empty.doc.mjs', 'export const unrelated = 1;\n');
|
|
114
114
|
await expect(loadDocs(file)).resolves.toBeUndefined();
|
|
115
|
-
await expect(loadComponentDoc(file)).rejects.toThrow(
|
|
115
|
+
await expect(loadComponentDoc(file)).rejects.toThrow(
|
|
116
|
+
`${file} has no default export or \`docs\` export (it exports \`unrelated\`), so it documents nothing. Fix: export the doc object as the default export`,
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('says a checked doc file is empty', async () => {
|
|
121
|
+
const file = write('Blank.doc.mjs', '// nothing yet\n');
|
|
122
|
+
await expect(loadComponentDoc(file)).rejects.toThrow(
|
|
123
|
+
`${file} is empty, so it documents nothing.`,
|
|
124
|
+
);
|
|
116
125
|
});
|
|
117
126
|
|
|
118
127
|
it('applies the translation a module exports for the reading language', async () => {
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file A topic split into a namespace of guides indexes each term once, a
|
|
5
5
|
* policy of the docs split itself (no spec clause states it). Below the CLI's own
|
|
6
|
-
* root namespaces (every one but `cli`, its command and API reference
|
|
6
|
+
* root namespaces (every one but `cli`, its command and API reference, and
|
|
7
|
+
* `authoring`, the integration guides `cli` held before this rule), a
|
|
7
8
|
* guide's search keywords are its own: none repeats a keyword its namespace,
|
|
8
9
|
* a sibling, or a guide of another split topic declares. A term several
|
|
9
10
|
* guides share belongs to their namespace, or to none.
|
|
@@ -45,7 +46,7 @@ describe('the keywords of a split topic', () => {
|
|
|
45
46
|
return doc?.name;
|
|
46
47
|
};
|
|
47
48
|
const roots = [...docs.values()]
|
|
48
|
-
.filter(doc => doc.type === 'namespace' && !parentOf(doc) && doc.name
|
|
49
|
+
.filter(doc => doc.type === 'namespace' && !parentOf(doc) && !['cli', 'authoring'].includes(doc.name))
|
|
49
50
|
.map(doc => doc.name);
|
|
50
51
|
expect(roots).toContain('layout');
|
|
51
52
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* the one adoption rule in its package that matches its group and kind. A
|
|
10
10
|
* placement that fails withdraws the doc; it never falls back to adoption. A
|
|
11
11
|
* doc with neither is a flat topic: it keeps its flat name as its route, and its
|
|
12
|
-
* home is the generated
|
|
12
|
+
* home is the generated level for its category. The CLI keeps its own routes: an
|
|
13
13
|
* integration's node that would take one is withdrawn with a diagnostic.
|
|
14
14
|
*
|
|
15
15
|
* @param {{namespaces: TreeNamespaceInput[], docs: TreeDocInput[], topics?: TreeTopicInput[]}} inputs
|
|
@@ -117,19 +117,39 @@ export const KIND_GROUPS: Readonly<Record<string, {
|
|
|
117
117
|
*/
|
|
118
118
|
/**
|
|
119
119
|
* A flat topic: a reference topic that no namespace places. The tree gives it
|
|
120
|
-
* a home in the generated
|
|
120
|
+
* a home in the generated level for its category (Guides or Foundations),
|
|
121
|
+
* under its own name.
|
|
121
122
|
* @typedef {object} TreeTopicInput
|
|
122
123
|
* @property {string} provider the package that owns the topic
|
|
123
124
|
* @property {string} providerId the provider's ProviderId
|
|
124
125
|
* @property {string} name the topic's name, which stays its route
|
|
125
126
|
* @property {string} title
|
|
126
127
|
* @property {string} summary
|
|
128
|
+
* @property {string | null} [category] the topic's sidebar group:
|
|
129
|
+
* `foundations` puts it in Foundations; anything else, in Guides
|
|
127
130
|
* @property {string} source where the topic comes from, for diagnostics
|
|
128
131
|
* @property {string[]} [aliases] every other name the topic answers to: the
|
|
129
132
|
* topics it replaced, directly or through a chain
|
|
130
133
|
*/
|
|
131
|
-
/**
|
|
132
|
-
|
|
134
|
+
/**
|
|
135
|
+
* The generated levels that hold the flat topics, by category
|
|
136
|
+
* (spec:AST-046 FR12). A topic keeps its own name as its route; its level is
|
|
137
|
+
* only where it sits. Readers see these titles in a topic's path, so each is
|
|
138
|
+
* a plain name for what the topics are.
|
|
139
|
+
*/
|
|
140
|
+
export const TOPIC_LEVELS: Readonly<{
|
|
141
|
+
guides: Readonly<{
|
|
142
|
+
route: "guides";
|
|
143
|
+
title: "Guides";
|
|
144
|
+
summary: "Guides that stand on their own: getting started, principles, theming, and working with AI. Each topic keeps its own name; open one by it.";
|
|
145
|
+
}>;
|
|
146
|
+
foundations: Readonly<{
|
|
147
|
+
route: "foundations";
|
|
148
|
+
title: "Foundations";
|
|
149
|
+
summary: "Color, elevation, icons, illustrations, motion, shape, and spacing: the visual foundations every component builds on. Each topic keeps its own name; open one by it.";
|
|
150
|
+
}>;
|
|
151
|
+
}>;
|
|
152
|
+
export function topicLevel(category: string | null | undefined): "guides" | "foundations";
|
|
133
153
|
export type NamespaceDoc = import("../../authoring/doctypes/namespace/type").NamespaceDoc;
|
|
134
154
|
export type DocPlacement = import("../../authoring/doctypes/base/type").DocPlacement;
|
|
135
155
|
export type CompilerDiagnostic = import("./diagnostics.mjs").CompilerDiagnostic;
|
|
@@ -200,7 +220,8 @@ export type TreeSlot = {
|
|
|
200
220
|
};
|
|
201
221
|
/**
|
|
202
222
|
* A flat topic: a reference topic that no namespace places. The tree gives it
|
|
203
|
-
* a home in the generated
|
|
223
|
+
* a home in the generated level for its category (Guides or Foundations),
|
|
224
|
+
* under its own name.
|
|
204
225
|
*/
|
|
205
226
|
export type TreeTopicInput = {
|
|
206
227
|
/**
|
|
@@ -217,6 +238,11 @@ export type TreeTopicInput = {
|
|
|
217
238
|
name: string;
|
|
218
239
|
title: string;
|
|
219
240
|
summary: string;
|
|
241
|
+
/**
|
|
242
|
+
* the topic's sidebar group:
|
|
243
|
+
* `foundations` puts it in Foundations; anything else, in Guides
|
|
244
|
+
*/
|
|
245
|
+
category?: string | null | undefined;
|
|
220
246
|
/**
|
|
221
247
|
* where the topic comes from, for diagnostics
|
|
222
248
|
*/
|
|
@@ -265,7 +291,7 @@ export type TreeNode = {
|
|
|
265
291
|
order: number | null;
|
|
266
292
|
/**
|
|
267
293
|
* made by the compiler (a `groupBy: 'kind'`
|
|
268
|
-
* level, or
|
|
294
|
+
* level, or a flat topics' level), not authored
|
|
269
295
|
*/
|
|
270
296
|
generated: boolean;
|
|
271
297
|
/**
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @position Between discovery and the readers: `astryx docs <route>`,
|
|
13
13
|
* `astryx doctor`, and the docsite build all read this tree. The CLI's docs
|
|
14
14
|
* and each integration's have a home here, and a flat topic's home is the
|
|
15
|
-
* generated
|
|
15
|
+
* generated level for its category: Guides or Foundations.
|
|
16
16
|
* A namespace never scans files and never lists its children: a child names
|
|
17
17
|
* its parent, or a namespace adopts a discovery group.
|
|
18
18
|
*/
|
|
@@ -113,20 +113,49 @@ export const KIND_GROUPS = Object.freeze({
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* A flat topic: a reference topic that no namespace places. The tree gives it
|
|
116
|
-
* a home in the generated
|
|
116
|
+
* a home in the generated level for its category (Guides or Foundations),
|
|
117
|
+
* under its own name.
|
|
117
118
|
* @typedef {object} TreeTopicInput
|
|
118
119
|
* @property {string} provider the package that owns the topic
|
|
119
120
|
* @property {string} providerId the provider's ProviderId
|
|
120
121
|
* @property {string} name the topic's name, which stays its route
|
|
121
122
|
* @property {string} title
|
|
122
123
|
* @property {string} summary
|
|
124
|
+
* @property {string | null} [category] the topic's sidebar group:
|
|
125
|
+
* `foundations` puts it in Foundations; anything else, in Guides
|
|
123
126
|
* @property {string} source where the topic comes from, for diagnostics
|
|
124
127
|
* @property {string[]} [aliases] every other name the topic answers to: the
|
|
125
128
|
* topics it replaced, directly or through a chain
|
|
126
129
|
*/
|
|
127
130
|
|
|
128
|
-
/**
|
|
129
|
-
|
|
131
|
+
/**
|
|
132
|
+
* The generated levels that hold the flat topics, by category
|
|
133
|
+
* (spec:AST-046 FR12). A topic keeps its own name as its route; its level is
|
|
134
|
+
* only where it sits. Readers see these titles in a topic's path, so each is
|
|
135
|
+
* a plain name for what the topics are.
|
|
136
|
+
*/
|
|
137
|
+
export const TOPIC_LEVELS = Object.freeze({
|
|
138
|
+
guides: Object.freeze({
|
|
139
|
+
route: 'guides',
|
|
140
|
+
title: 'Guides',
|
|
141
|
+
summary:
|
|
142
|
+
'Guides that stand on their own: getting started, principles, theming, and working with AI. Each topic keeps its own name; open one by it.',
|
|
143
|
+
}),
|
|
144
|
+
foundations: Object.freeze({
|
|
145
|
+
route: 'foundations',
|
|
146
|
+
title: 'Foundations',
|
|
147
|
+
summary:
|
|
148
|
+
'Color, elevation, icons, illustrations, motion, shape, and spacing: the visual foundations every component builds on. Each topic keeps its own name; open one by it.',
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The generated level a flat topic sits in.
|
|
154
|
+
* @param {string | null | undefined} category
|
|
155
|
+
* @returns {'guides' | 'foundations'}
|
|
156
|
+
*/
|
|
157
|
+
export const topicLevel = category =>
|
|
158
|
+
category === 'foundations' ? 'foundations' : 'guides';
|
|
130
159
|
|
|
131
160
|
/**
|
|
132
161
|
* @typedef {object} TreeNode
|
|
@@ -145,7 +174,7 @@ export const UNORGANIZED = 'unorganized';
|
|
|
145
174
|
* @property {string | null} slot the parent slot this node sits in
|
|
146
175
|
* @property {number | null} order
|
|
147
176
|
* @property {boolean} generated made by the compiler (a `groupBy: 'kind'`
|
|
148
|
-
* level, or
|
|
177
|
+
* level, or a flat topics' level), not authored
|
|
149
178
|
* @property {TreeSlot[]} slots a namespace's slots; empty for a leaf
|
|
150
179
|
* @property {string} source
|
|
151
180
|
* @property {any} [ref]
|
|
@@ -216,7 +245,7 @@ function resolveParent(parent, provider, declared) {
|
|
|
216
245
|
* the one adoption rule in its package that matches its group and kind. A
|
|
217
246
|
* placement that fails withdraws the doc; it never falls back to adoption. A
|
|
218
247
|
* doc with neither is a flat topic: it keeps its flat name as its route, and its
|
|
219
|
-
* home is the generated
|
|
248
|
+
* home is the generated level for its category. The CLI keeps its own routes: an
|
|
220
249
|
* integration's node that would take one is withdrawn with a diagnostic.
|
|
221
250
|
*
|
|
222
251
|
* @param {{namespaces: TreeNamespaceInput[], docs: TreeDocInput[], topics?: TreeTopicInput[]}} inputs
|
|
@@ -237,10 +266,15 @@ export function buildDocsTree({namespaces, docs, topics = []}) {
|
|
|
237
266
|
);
|
|
238
267
|
|
|
239
268
|
// Routes the CLI's own docs keep (spec:AST-046 FR11): the name of each of
|
|
240
|
-
// its flat topics, and the generated
|
|
241
|
-
// theirs by rank, because they go into the tree first.
|
|
242
|
-
// without case, as topic names do, so `CLI` claims `cli`.
|
|
243
|
-
|
|
269
|
+
// its flat topics, and the generated levels that hold flat topics. Its
|
|
270
|
+
// namespaces keep theirs by rank, because they go into the tree first.
|
|
271
|
+
// Routes compare without case, as topic names do, so `CLI` claims `cli`.
|
|
272
|
+
/** @type {Set<string>} */
|
|
273
|
+
const cliRoutes = new Set(
|
|
274
|
+
topics.length > 0
|
|
275
|
+
? Object.values(TOPIC_LEVELS).map(level => level.route)
|
|
276
|
+
: [],
|
|
277
|
+
);
|
|
244
278
|
for (const topic of topics) {
|
|
245
279
|
if (topic.provider === CLI_PROVIDER)
|
|
246
280
|
cliRoutes.add(topic.name.toLowerCase());
|
|
@@ -592,20 +626,21 @@ export function buildDocsTree({namespaces, docs, topics = []}) {
|
|
|
592
626
|
);
|
|
593
627
|
}
|
|
594
628
|
|
|
595
|
-
// The generated
|
|
596
|
-
//
|
|
597
|
-
// tree. A topic keeps its own name as its route.
|
|
598
|
-
|
|
629
|
+
// The generated levels (spec:AST-046 FR12): every flat topic sits in the
|
|
630
|
+
// level for its category, in the order the topic list reads, so every doc
|
|
631
|
+
// has a named home in the tree. A topic keeps its own name as its route.
|
|
632
|
+
for (const [key, level] of Object.entries(TOPIC_LEVELS)) {
|
|
633
|
+
const members = topics.filter(topic => topicLevel(topic.category) === key);
|
|
634
|
+
if (members.length === 0) continue;
|
|
599
635
|
const home = {
|
|
600
636
|
id: null,
|
|
601
|
-
route:
|
|
637
|
+
route: level.route,
|
|
602
638
|
kind: 'namespace',
|
|
603
639
|
provider: CLI_PROVIDER,
|
|
604
640
|
providerId: CLI_PROVIDER_ID,
|
|
605
|
-
name:
|
|
606
|
-
title:
|
|
607
|
-
summary:
|
|
608
|
-
'Every topic that no section places yet. Each keeps its own name; open one by it.',
|
|
641
|
+
name: level.route,
|
|
642
|
+
title: level.title,
|
|
643
|
+
summary: level.summary,
|
|
609
644
|
parent: null,
|
|
610
645
|
slot: null,
|
|
611
646
|
order: null,
|
|
@@ -613,30 +648,29 @@ export function buildDocsTree({namespaces, docs, topics = []}) {
|
|
|
613
648
|
slots: [{name: 'topics', title: 'Topics', children: []}],
|
|
614
649
|
source: 'generated',
|
|
615
650
|
};
|
|
616
|
-
if (addNode(home, {provider: CLI_PROVIDER, source: 'generated'}))
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
}
|
|
651
|
+
if (!addNode(home, {provider: CLI_PROVIDER, source: 'generated'})) continue;
|
|
652
|
+
members.forEach((topic, i) => {
|
|
653
|
+
addNode(
|
|
654
|
+
{
|
|
655
|
+
id: createDocId(topic.providerId, 'generic', topic.name),
|
|
656
|
+
route: topic.name,
|
|
657
|
+
kind: 'generic',
|
|
658
|
+
provider: topic.provider,
|
|
659
|
+
providerId: topic.providerId,
|
|
660
|
+
name: topic.name,
|
|
661
|
+
title: topic.title,
|
|
662
|
+
summary: topic.summary,
|
|
663
|
+
parent: level.route,
|
|
664
|
+
slot: 'topics',
|
|
665
|
+
order: i,
|
|
666
|
+
generated: false,
|
|
667
|
+
slots: [],
|
|
668
|
+
source: topic.source,
|
|
669
|
+
ref: {flatTopic: topic.name},
|
|
670
|
+
},
|
|
671
|
+
topic,
|
|
672
|
+
);
|
|
673
|
+
});
|
|
640
674
|
}
|
|
641
675
|
|
|
642
676
|
// Children, per slot, in reading order: order, then title, then id.
|