@astryxdesign/cli 0.7.2-canary.fdd384f → 0.7.2
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/CHANGELOG.md +119 -0
- package/README.md +169 -149
- package/api/build/_adapter.d.mts +8 -0
- package/api/build/_adapter.mjs +12 -1
- package/api/build/build.doc.mjs +4 -0
- package/api/build/kit/kit.mjs +3 -11
- package/api/component/_adapter.d.mts +31 -0
- package/api/component/_adapter.mjs +119 -11
- package/api/component/component.doc.mjs +6 -1
- package/api/component/component.mjs +60 -10
- package/api/component/doc-links.test.mjs +386 -0
- package/api/discover/_adapter.d.mts +132 -12
- package/api/discover/_adapter.mjs +488 -27
- package/api/discover/_adapter.test.mjs +599 -17
- package/api/discover/_catalog-view.d.mts +16 -5
- package/api/discover/_catalog-view.mjs +32 -8
- package/api/discover/detail/doc/doc.mjs +9 -1
- package/api/discover/discover.d.mts +11 -0
- package/api/discover/discover.doc.mjs +9 -7
- package/api/discover/discover.mjs +121 -19
- package/api/discover/discover.type.d.mts +20 -7
- package/api/discover/discover.type.mjs +17 -7
- package/api/discover/list/list.d.mts +4 -3
- package/api/discover/list/list.mjs +17 -10
- package/api/docs/_adapter.d.mts +63 -0
- package/api/docs/_adapter.mjs +312 -18
- package/api/docs/docs.doc.mjs +2 -1
- package/api/docs/docs.mjs +2 -1
- package/api/docs/docs.test.mjs +5 -2
- package/api/docs/integration-tree.test.mjs +22 -0
- package/api/docs/list/list.mjs +12 -2
- package/api/docs/reference-blocks.test.mjs +1 -3
- package/api/doctor/_adapter.d.mts +108 -0
- package/api/doctor/_adapter.mjs +223 -4
- package/api/doctor/doctor.d.mts +199 -0
- package/api/doctor/doctor.doc.mjs +3 -2
- package/api/doctor/doctor.mjs +530 -34
- package/api/doctor/doctor.test.mjs +180 -14
- package/api/doctor/release-checks.test.mjs +156 -0
- package/api/doctor/theme-checks.mjs +16 -3
- package/api/doctor/theme-checks.test.mjs +223 -7
- package/api/error.d.mts +10 -0
- package/api/error.mjs +25 -0
- package/api/gap-report/gap-report.d.mts +3 -0
- package/api/gap-report/gap-report.doc.mjs +11 -3
- package/api/gap-report/gap-report.mjs +152 -48
- package/api/gap-report/gap-report.test.mjs +233 -0
- package/api/gap-report/gap-report.type.d.mts +41 -0
- package/api/gap-report/gap-report.type.mjs +18 -0
- package/api/hook/_adapter.mjs +3 -11
- package/api/hook/hook.doc.mjs +4 -0
- package/api/hook/list/list.d.mts +1 -1
- package/api/init/_adapter.d.mts +22 -0
- package/api/init/_adapter.mjs +59 -0
- package/api/init/init.d.mts +7 -5
- package/api/init/init.doc.mjs +28 -7
- package/api/init/init.mjs +28 -4
- package/api/init/init.type.d.mts +48 -3
- package/api/init/init.type.mjs +37 -3
- package/api/init/run/run.d.mts +1 -1
- package/api/init/run/run.mjs +15 -4
- package/api/init/user/user.d.mts +14 -0
- package/api/init/user/user.mjs +87 -0
- package/api/init/user/user.test.mjs +232 -0
- package/api/integration/_adapter.d.mts +33 -0
- package/api/integration/_adapter.mjs +58 -0
- package/api/integration/authoring-checks.mjs +100 -5
- package/api/integration/authoring-checks.test.mjs +769 -0
- package/api/integration/authoring-checks.type.d.mts +134 -0
- package/api/integration/authoring-checks.type.mjs +60 -1
- package/api/integration/integrationCheck.doc.mjs +1 -1
- package/api/integration/integrationComponentConflicts.doc.mjs +11 -3
- package/api/integration/integrationDocConflicts.doc.mjs +22 -5
- package/api/integration/pack-check.mjs +303 -13
- package/api/integration/pack-check.test.mjs +371 -10
- package/api/integration/validate-integration-fixes.test.mjs +67 -0
- package/api/integration/validate-integration.d.mts +8 -0
- package/api/integration/validate-integration.mjs +55 -9
- package/api/integration/validate-integration.test.mjs +77 -8
- package/api/integration/validate-integration.type.d.mts +8 -0
- package/api/integration/validate-integration.type.mjs +3 -1
- package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
- package/api/integration/validateIntegration.doc.mjs +4 -2
- package/api/search/_adapter.d.mts +11 -0
- package/api/search/_adapter.mjs +25 -0
- package/api/search/search.d.mts +73 -13
- package/api/search/search.doc.mjs +8 -3
- package/api/search/search.domain-priority.test.mjs +108 -18
- package/api/search/search.mjs +541 -52
- package/api/search/search.test.mjs +143 -1
- package/api/search/search.type.d.mts +14 -1
- package/api/search/search.type.mjs +6 -1
- package/api/swizzle/_adapter.mjs +2 -2
- package/api/swizzle/copy/copy.mjs +1 -1
- package/api/template/template-integration.test.mjs +1 -1
- package/api/theme/_adapter.d.mts +16 -0
- package/api/theme/_adapter.mjs +32 -5
- package/api/theme/build/build.d.mts +2 -1
- package/api/theme/build/build.mjs +70 -14
- package/api/theme/build/build.packed-old-core.test.mjs +20 -3
- package/api/theme/build/font-warning.mjs +5 -3
- package/api/theme/build/font-warning.test.mjs +2 -1
- package/api/theme/remove/remove.test.mjs +2 -2
- package/api/theme/targets/targets.mjs +3 -10
- package/api/theme/themeTargets.doc.mjs +4 -0
- package/api/theme/use/use.test.mjs +1 -1
- package/api/upgrade/_adapter.d.mts +40 -2
- package/api/upgrade/_adapter.mjs +118 -5
- package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
- package/api/upgrade/run/run.mjs +35 -2
- package/api/upgrade/status/status.d.mts +21 -5
- package/api/upgrade/status/status.mjs +45 -8
- package/api/upgrade/upgrade.doc.mjs +6 -3
- package/api/upgrade/upgrade.mjs +5 -1
- package/api/upgrade/upgrade.type.d.mts +23 -0
- package/api/upgrade/upgrade.type.mjs +16 -1
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/registry.mjs +1 -0
- package/assets/codemods/runner.mjs +7 -1
- package/assets/codemods/transforms/next/index.mjs +1 -11
- package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
- package/assets/discover/official-packages.json +367 -0
- package/assets/docs/author-a-theme.doc.mjs +2 -2
- package/assets/docs/browser-support.doc.mjs +1 -1
- package/assets/docs/getting-started.doc.mjs +23 -3
- package/assets/docs/styling-overview.doc.mjs +1 -1
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-component.doc.mjs +12 -2
- package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
- package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
- package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
- package/assets/docs/tree/block-template.doc.mjs +6 -18
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +4 -0
- package/assets/docs/tree/check-the-props.doc.mjs +8 -3
- package/assets/docs/tree/check-your-docs.doc.mjs +30 -13
- package/assets/docs/tree/checks.doc.mjs +17 -17
- package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
- package/assets/docs/tree/cli-command.doc.mjs +142 -0
- package/assets/docs/tree/cli.doc.mjs +6 -0
- package/assets/docs/tree/codemods.doc.mjs +17 -7
- package/assets/docs/tree/commands.doc.mjs +7 -1
- package/assets/docs/tree/component-family.doc.mjs +3 -5
- package/assets/docs/tree/component-imports.doc.mjs +13 -3
- package/assets/docs/tree/components.doc.mjs +7 -1
- package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
- package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
- package/assets/docs/tree/configuration.doc.mjs +7 -3
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
- package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
- package/assets/docs/tree/describe-the-component.doc.mjs +2 -2
- package/assets/docs/tree/docs.doc.mjs +9 -3
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
- package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
- package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
- package/assets/docs/tree/global-integrations.doc.mjs +124 -0
- package/assets/docs/tree/global.doc.mjs +131 -0
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
- package/assets/docs/tree/install-once.doc.mjs +105 -0
- package/assets/docs/tree/integrations.doc.mjs +13 -1
- package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
- package/assets/docs/tree/layout.doc.mjs +6 -6
- package/assets/docs/tree/links.doc.mjs +6 -5
- package/assets/docs/tree/migration-setup.doc.mjs +3 -2
- package/assets/docs/tree/migration-verification.doc.mjs +0 -1
- package/assets/docs/tree/migration.doc.mjs +0 -1
- package/assets/docs/tree/monorepos.doc.mjs +84 -0
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +3 -7
- package/assets/docs/tree/problems.doc.mjs +205 -0
- package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
- package/assets/docs/tree/publishing.doc.mjs +6 -6
- package/assets/docs/tree/quick-start.doc.mjs +52 -26
- package/assets/docs/tree/reference.doc.mjs +192 -0
- package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
- package/assets/docs/tree/replace-a-core-template.doc.mjs +9 -11
- package/assets/docs/tree/scaffold.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
- package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
- package/assets/docs/tree/single-component.doc.mjs +14 -6
- package/assets/docs/tree/start-a-template.doc.mjs +18 -8
- package/assets/docs/tree/subcomponent.doc.mjs +6 -6
- package/assets/docs/tree/template-assets.doc.mjs +2 -2
- package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- 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 +2 -2
- package/assets/docs/tree/templates.doc.mjs +7 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
- package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
- package/assets/docs/tree/themes.doc.mjs +4 -0
- package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
- package/assets/docs/tree/troubleshooting.doc.mjs +22 -14
- package/assets/docs/tree/uninstall.doc.mjs +109 -0
- package/assets/docs/tree/updates.doc.mjs +92 -0
- package/assets/docs/tree/upgrading.doc.mjs +6 -6
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
- package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
- package/assets/docs/tree/versioning.doc.mjs +9 -9
- package/assets/docs/tree/who-answers.doc.mjs +119 -0
- package/assets/docs/tree/write-the-template-file.doc.mjs +5 -5
- package/assets/docs/working-with-ai.doc.mjs +23 -9
- package/authoring/codemod/codemod.doc.mjs +7 -3
- package/authoring/config/config.doc.mjs +9 -6
- package/authoring/config/type.ts +4 -2
- package/authoring/debug/parse.d.mts +5 -5
- package/authoring/discover/discover.doc.mjs +7 -1
- package/authoring/doctypes/_schema.d.mts +8 -3
- package/authoring/doctypes/_schema.mjs +1 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
- package/authoring/doctypes/command/command.doc.mjs +20 -12
- package/authoring/doctypes/command/type.ts +14 -0
- package/authoring/doctypes/component/component.doc.mjs +29 -26
- package/authoring/doctypes/component/type.ts +15 -5
- package/authoring/doctypes/enum/enum.doc.mjs +7 -4
- package/authoring/doctypes/function/function.doc.mjs +9 -8
- package/authoring/doctypes/hook/hook.doc.mjs +5 -4
- package/authoring/doctypes/hook/type.ts +4 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
- package/authoring/doctypes/reference/reference.doc.mjs +12 -11
- package/authoring/doctypes/schema/schema.doc.mjs +9 -9
- package/authoring/doctypes/template/template.doc.mjs +2 -2
- package/authoring/doctypes/theme/theme.doc.mjs +2 -2
- package/authoring/gap-report/gap-report.doc.mjs +2 -2
- package/authoring/identity/identity.doc.mjs +3 -3
- package/authoring/index.d.ts +1 -0
- package/authoring/integration/integration.doc.mjs +22 -5
- package/authoring/integration/parse.test.mjs +11 -0
- package/authoring/integration/schema.d.mts +14 -3
- package/authoring/integration/schema.mjs +33 -2
- package/authoring/integration/type.ts +8 -0
- package/clients/cli/bin/astryx.mjs +20 -3
- package/clients/cli/cli-command.test.mjs +166 -0
- package/clients/cli/commands/blog.doc.mjs +1 -0
- package/clients/cli/commands/build-theme.batch-report.test.mjs +14 -2
- package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
- package/clients/cli/commands/build-theme.mjs +25 -12
- package/clients/cli/commands/build.doc.mjs +1 -0
- package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
- package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
- package/clients/cli/commands/component.doc.mjs +1 -0
- package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
- package/clients/cli/commands/discover.doc.mjs +9 -1
- package/clients/cli/commands/discover.mjs +144 -93
- package/clients/cli/commands/discover.no-source.test.mjs +448 -33
- package/clients/cli/commands/discover.sources.test.mjs +20 -1
- package/clients/cli/commands/docs.doc.mjs +1 -0
- package/clients/cli/commands/docs.mjs +49 -19
- package/clients/cli/commands/docs.test.mjs +2 -2
- package/clients/cli/commands/doctor-integration-components.doc.mjs +7 -3
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +13 -2
- package/clients/cli/commands/doctor-integration.test.mjs +52 -4
- package/clients/cli/commands/doctor.doc.mjs +12 -2
- package/clients/cli/commands/doctor.mjs +102 -7
- package/clients/cli/commands/doctor.test.mjs +10 -4
- package/clients/cli/commands/gap-report.doc.mjs +15 -2
- package/clients/cli/commands/gap-report.mjs +24 -2
- package/clients/cli/commands/gap-report.test.mjs +79 -0
- package/clients/cli/commands/hook.doc.mjs +1 -0
- package/clients/cli/commands/init.behavior.test.mjs +5 -0
- package/clients/cli/commands/init.doc.mjs +29 -3
- package/clients/cli/commands/integration-add.doc.mjs +7 -0
- package/clients/cli/commands/integration-authoring.test.mjs +49 -3
- package/clients/cli/commands/integration-check.doc.mjs +10 -2
- package/clients/cli/commands/integration-check.test.mjs +175 -1
- package/clients/cli/commands/integration-pack.doc.mjs +8 -1
- package/clients/cli/commands/integration-verify.doc.mjs +8 -1
- package/clients/cli/commands/integration.mjs +15 -9
- package/clients/cli/commands/json-contract.test.mjs +11 -2
- package/clients/cli/commands/manifest.doc.mjs +1 -0
- package/clients/cli/commands/outside-project.test.mjs +774 -0
- package/clients/cli/commands/search.doc.mjs +1 -0
- package/clients/cli/commands/search.mjs +16 -11
- package/clients/cli/commands/search.test.mjs +429 -296
- package/clients/cli/commands/setup-nudge.test.mjs +102 -2
- package/clients/cli/commands/swizzle.doc.mjs +7 -0
- package/clients/cli/commands/swizzle.mjs +5 -3
- package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
- package/clients/cli/commands/template.doc.mjs +1 -0
- package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
- package/clients/cli/commands/theme-add.doc.mjs +8 -1
- package/clients/cli/commands/theme-build.doc.mjs +1 -0
- package/clients/cli/commands/theme-eject.doc.mjs +1 -0
- package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
- package/clients/cli/commands/theme-list.doc.mjs +1 -0
- package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
- package/clients/cli/commands/theme-remove.doc.mjs +7 -0
- package/clients/cli/commands/theme-targets.doc.mjs +1 -0
- package/clients/cli/commands/theme-template.doc.mjs +1 -0
- package/clients/cli/commands/theme-use.doc.mjs +7 -0
- package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
- package/clients/cli/commands/upgrade.doc.mjs +22 -1
- package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
- package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
- package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
- package/clients/cli/index.mjs +111 -16
- package/clients/cli/lib/cli-error.mjs +4 -1
- package/clients/cli/lib/component-format.test.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +2 -2
- package/clients/cli/lib/json-shim.mjs +3 -1
- package/clients/cli/lib/manifest.d.ts +9 -0
- package/clients/cli/lib/manifest.mjs +17 -1
- package/clients/cli/lib/manifest.test.mjs +25 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
- package/foundation/agent-docs/agent-doc-state.mjs +66 -6
- package/foundation/agent-docs/agent-docs.d.mts +4 -3
- package/foundation/agent-docs/agent-docs.mjs +11 -9
- package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
- package/foundation/agent-docs/computer-agent-text.mjs +623 -0
- package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
- package/foundation/config/project.d.mts +35 -3
- package/foundation/config/project.mjs +145 -8
- package/foundation/config/project.test.mjs +66 -0
- package/foundation/config/theme-state.mjs +5 -4
- package/foundation/discovery/authoring-self-docs.mjs +1 -1
- package/foundation/discovery/cli-self-docs.mjs +20 -3
- package/foundation/discovery/cli-self-docs.test.mjs +3 -2
- package/foundation/discovery/component-replacement.mjs +2 -1
- package/foundation/discovery/copied-passages.d.mts +216 -0
- package/foundation/discovery/copied-passages.mjs +720 -0
- package/foundation/discovery/copied-passages.test.mjs +124 -0
- package/foundation/discovery/doc-consistency.d.mts +34 -0
- package/foundation/discovery/doc-consistency.mjs +513 -0
- package/foundation/discovery/doc-consistency.test.mjs +347 -0
- package/foundation/discovery/doc-fluff.d.mts +112 -0
- package/foundation/discovery/doc-fluff.mjs +328 -0
- package/foundation/discovery/doc-fluff.test.mjs +142 -0
- package/foundation/discovery/doc-types.d.mts +1 -1
- package/foundation/discovery/doc-types.mjs +15 -8
- package/foundation/discovery/doc-types.test.mjs +94 -2
- package/foundation/discovery/docs-discovery.d.mts +7 -0
- package/foundation/discovery/docs-discovery.mjs +26 -2
- package/foundation/discovery/project-typescript.d.mts +11 -2
- package/foundation/discovery/project-typescript.mjs +32 -4
- package/foundation/discovery/prop-drift.d.mts +26 -7
- package/foundation/discovery/prop-drift.mjs +173 -8
- package/foundation/discovery/prop-drift.test.mjs +120 -2
- package/foundation/discovery/runner-allowlist.d.mts +40 -0
- package/foundation/discovery/runner-allowlist.mjs +53 -0
- package/foundation/discovery/stray-pointers.d.mts +52 -0
- package/foundation/discovery/stray-pointers.mjs +293 -0
- package/foundation/discovery/stray-pointers.test.mjs +86 -0
- package/foundation/discovery/template-needs.mjs +5 -2
- package/foundation/discovery/theme-imports.mjs +8 -4
- package/foundation/discovery/theme-imports.test.mjs +1 -1
- package/foundation/discovery/type-text.mjs +1 -1
- package/foundation/discovery/type-text.test.mjs +1 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +42 -2
- package/foundation/doc-compiler/inputs.mjs +4 -1
- package/foundation/doc-compiler/links.d.mts +32 -0
- package/foundation/doc-compiler/links.mjs +163 -26
- package/foundation/doc-compiler/links.test.mjs +97 -4
- package/foundation/doc-compiler/read.d.mts +1 -1
- package/foundation/doc-compiler/tree.mjs +30 -1
- package/foundation/doc-compiler/tree.test.mjs +8 -1
- package/foundation/env/cli-command.d.mts +83 -0
- package/foundation/env/cli-command.mjs +152 -0
- package/foundation/env/cli-command.test.mjs +129 -0
- package/foundation/env/node-version.test.mjs +15 -3
- package/foundation/env/package-manager.d.mts +93 -9
- package/foundation/env/package-manager.global.test.mjs +66 -0
- package/foundation/env/package-manager.mjs +184 -13
- package/foundation/env/package-manager.test.mjs +341 -15
- package/foundation/env/project-scope.d.mts +9 -0
- package/foundation/env/project-scope.mjs +33 -0
- package/foundation/env/search-path.d.mts +42 -0
- package/foundation/env/search-path.mjs +205 -0
- package/foundation/env/search-path.test.mjs +122 -0
- package/foundation/env/user-dirs.d.mts +39 -0
- package/foundation/env/user-dirs.mjs +93 -0
- package/foundation/env/user-dirs.test.mjs +72 -0
- package/foundation/env/user-settings.d.mts +46 -0
- package/foundation/env/user-settings.mjs +106 -0
- package/foundation/env/user-settings.test.mjs +64 -0
- package/foundation/fs/file-protection.mjs +15 -1
- package/foundation/fs/module-loader.d.mts +2 -1
- package/foundation/fs/module-loader.mjs +60 -4
- package/foundation/fs/module-loader.stdout.test.mjs +3 -2
- package/foundation/fs/module-loader.test.mjs +194 -0
- package/foundation/fs/path-compare.d.mts +33 -0
- package/foundation/fs/path-compare.mjs +73 -0
- package/foundation/fs/paths.d.mts +57 -1
- package/foundation/fs/paths.mjs +131 -3
- package/foundation/fs/paths.test.mjs +10 -1
- package/foundation/integrations/computer-integrations.d.mts +78 -0
- package/foundation/integrations/computer-integrations.mjs +316 -0
- package/foundation/integrations/computer-integrations.test.mjs +292 -0
- package/foundation/integrations/contribution-inventory.d.mts +11 -0
- package/foundation/integrations/contribution-inventory.mjs +50 -2
- package/foundation/integrations/integration-warnings.mjs +3 -2
- package/foundation/integrations/integration-warnings.test.mjs +8 -9
- package/foundation/integrations/integrations.d.mts +25 -1
- package/foundation/integrations/integrations.mjs +46 -3
- package/foundation/integrations/issue.ts +6 -0
- package/foundation/integrations/validate-contributions.d.mts +2 -0
- package/foundation/integrations/validate-contributions.mjs +41 -1
- package/foundation/release/agent-text-worker.d.mts +4 -0
- package/foundation/release/agent-text-worker.mjs +52 -0
- package/foundation/release/cache.d.mts +310 -0
- package/foundation/release/cache.mjs +1216 -0
- package/foundation/release/cache.test.mjs +920 -0
- package/foundation/release/choose.d.mts +207 -0
- package/foundation/release/choose.mjs +677 -0
- package/foundation/release/choose.test.mjs +427 -0
- package/foundation/release/core-worker.d.mts +4 -0
- package/foundation/release/core-worker.mjs +38 -0
- package/foundation/release/global-state.d.mts +259 -0
- package/foundation/release/global-state.mjs +472 -0
- package/foundation/release/global-state.test.mjs +381 -0
- package/foundation/release/handoff.d.mts +60 -0
- package/foundation/release/handoff.e2e.test.mjs +278 -0
- package/foundation/release/handoff.mjs +357 -0
- package/foundation/release/lock-lease.d.mts +23 -0
- package/foundation/release/lock-lease.mjs +80 -0
- package/foundation/release/notices.d.mts +253 -0
- package/foundation/release/notices.mjs +596 -0
- package/foundation/release/notices.test.mjs +565 -0
- package/foundation/release/npm-guard.d.mts +4 -0
- package/foundation/release/npm-guard.mjs +126 -0
- package/foundation/release/project.d.mts +141 -0
- package/foundation/release/project.mjs +466 -0
- package/foundation/release/project.test.mjs +288 -0
- package/foundation/release/refresh-worker.d.mts +4 -0
- package/foundation/release/refresh-worker.mjs +27 -0
- package/foundation/release/run-context.d.mts +47 -0
- package/foundation/release/run-context.mjs +149 -0
- package/foundation/release/update-notice-env.d.mts +28 -0
- package/foundation/release/update-notice-env.mjs +39 -0
- package/foundation/response/base.d.ts +26 -3
- package/foundation/response/error-codes.d.mts +3 -1
- package/foundation/response/error-codes.doc.mjs +12 -0
- package/foundation/response/error-codes.mjs +17 -0
- package/foundation/response/error-codes.test.mjs +2 -0
- package/foundation/response/json-contract.test.mjs +7 -2
- package/foundation/response/json.mjs +4 -1
- package/foundation/response/response-types.doc.mjs +17 -11
- package/foundation/response/response-types.doc.test.mjs +46 -0
- package/foundation/response/response.doc.mjs +3 -3
- package/foundation/xle/browser-imports.test.mjs +74 -0
- package/package.json +11 -11
- package/scripts/postinstall.mjs +24 -5
- /package/assets/codemods/transforms/{next → v0.7.2}/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +0 -0
- /package/assets/codemods/transforms/{next → v0.7.2}/migrate-list-edge-compensation-to-edge.mjs +0 -0
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
tokenizeQuery,
|
|
37
37
|
SEARCH_DOMAINS,
|
|
38
38
|
} from './search.mjs';
|
|
39
|
+
import {linkThisCliAsProjectCli} from '../../test-utils/release-fixtures.mjs';
|
|
39
40
|
|
|
40
41
|
const REPO = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
|
|
41
42
|
const cwd = REPO;
|
|
@@ -470,8 +471,10 @@ describe('search leaf — error paths (pinned)', () => {
|
|
|
470
471
|
|
|
471
472
|
it('searches the docs without @astryxdesign/core, and throws for a domain that needs it', async () => {
|
|
472
473
|
const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-search-no-core-'));
|
|
474
|
+
// A project whose own CLI answers, with no Core installed.
|
|
475
|
+
linkThisCliAsProjectCli(empty);
|
|
473
476
|
try {
|
|
474
|
-
// An open search
|
|
477
|
+
// An open search without Core covers the docs, as `astryx docs` does.
|
|
475
478
|
const open = await search('make an integration', {cwd: empty});
|
|
476
479
|
expect(open.data.results.length).toBeGreaterThan(0);
|
|
477
480
|
expect(new Set(open.data.results.map(r => r.domain))).toEqual(
|
|
@@ -863,3 +866,142 @@ describe('search — usage guidance is indexed, a tier below description', () =>
|
|
|
863
866
|
expect(hit?.score).toBe(45);
|
|
864
867
|
});
|
|
865
868
|
});
|
|
869
|
+
|
|
870
|
+
describe('search leaf — compound names, other names, and word forms', () => {
|
|
871
|
+
it('finds a compound name typed as separate words inside a longer query', async () => {
|
|
872
|
+
const {data} = await search('table header cell with sort arrow', {cwd});
|
|
873
|
+
expect(
|
|
874
|
+
data.results.slice(0, 3).map(r => r.name),
|
|
875
|
+
).toContain('TableHeaderCell');
|
|
876
|
+
}, SLOW);
|
|
877
|
+
|
|
878
|
+
it('finds a one-word keyword typed as separate words', async () => {
|
|
879
|
+
// MetadataList declares `keyvalue`.
|
|
880
|
+
const {data} = await search('key value pairs', {cwd});
|
|
881
|
+
expect(data.results[0]).toMatchObject({
|
|
882
|
+
domain: 'component',
|
|
883
|
+
name: 'MetadataList',
|
|
884
|
+
});
|
|
885
|
+
}, SLOW);
|
|
886
|
+
|
|
887
|
+
it('finds a hook named by its words without the `use` prefix', async () => {
|
|
888
|
+
const {data} = await search('persisted table column settings', {cwd});
|
|
889
|
+
expect(data.results[0]).toMatchObject({
|
|
890
|
+
domain: 'hook',
|
|
891
|
+
name: 'useTableColumnSettings',
|
|
892
|
+
});
|
|
893
|
+
}, SLOW);
|
|
894
|
+
|
|
895
|
+
it('reads a camelCase identifier as the words it spells', async () => {
|
|
896
|
+
const {data} = await search('useTablePaginationState', {cwd});
|
|
897
|
+
expect(data.results[0]).toMatchObject({
|
|
898
|
+
domain: 'hook',
|
|
899
|
+
name: 'useTablePagination',
|
|
900
|
+
});
|
|
901
|
+
}, SLOW);
|
|
902
|
+
|
|
903
|
+
it('keeps each identifier of a multi-word query whole', async () => {
|
|
904
|
+
const {data} = await search('ChatMessageList ChatComposer', {cwd});
|
|
905
|
+
expect(data.results.slice(0, 2).map(r => r.name).sort()).toEqual([
|
|
906
|
+
'ChatComposer',
|
|
907
|
+
'ChatMessageList',
|
|
908
|
+
]);
|
|
909
|
+
}, SLOW);
|
|
910
|
+
|
|
911
|
+
it("finds a component by another library's name for it", async () => {
|
|
912
|
+
for (const [q, name] of [
|
|
913
|
+
['ScrollArea viewport', 'ScrollableArea'],
|
|
914
|
+
['toggle group of buttons', 'ToggleButtonGroup'],
|
|
915
|
+
['circular progress for uploads', 'Spinner'],
|
|
916
|
+
]) {
|
|
917
|
+
const {data} = await search(q, {cwd});
|
|
918
|
+
expect(data.results[0], q).toMatchObject({domain: 'component', name});
|
|
919
|
+
}
|
|
920
|
+
}, SLOW);
|
|
921
|
+
|
|
922
|
+
it('reads a one-identifier other name as typed', async () => {
|
|
923
|
+
const {data} = await search('AppHeader', {cwd});
|
|
924
|
+
expect(data.results[0]).toMatchObject({
|
|
925
|
+
domain: 'component',
|
|
926
|
+
name: 'LayoutHeader',
|
|
927
|
+
});
|
|
928
|
+
}, SLOW);
|
|
929
|
+
|
|
930
|
+
it('adds no near siblings beside an entry the query names outright', async () => {
|
|
931
|
+
const {data} = await search('top nav mega menu', {cwd});
|
|
932
|
+
expect(data.results[0]).toMatchObject({name: 'TopNavMegaMenu'});
|
|
933
|
+
// Its sub-parts start with its name; read joined they would score in the
|
|
934
|
+
// whole-name tier right under it.
|
|
935
|
+
const siblings = data.results.filter(
|
|
936
|
+
r => r.name !== 'TopNavMegaMenu' && r.name.startsWith('TopNavMegaMenu'),
|
|
937
|
+
);
|
|
938
|
+
for (const sibling of siblings) expect(sibling.score).toBeLessThan(190);
|
|
939
|
+
}, SLOW);
|
|
940
|
+
|
|
941
|
+
it('ranks an entry the query names above a match on part of another name', async () => {
|
|
942
|
+
// `table header` names TableHeader; useTableStickyColumns only holds the
|
|
943
|
+
// words `sticky columns`.
|
|
944
|
+
const {data} = await search('table header with sticky columns', {cwd});
|
|
945
|
+
const names = data.results.map(r => r.name);
|
|
946
|
+
expect(names.indexOf('TableHeader')).toBeLessThan(
|
|
947
|
+
names.indexOf('useTableStickyColumns') === -1
|
|
948
|
+
? Infinity
|
|
949
|
+
: names.indexOf('useTableStickyColumns'),
|
|
950
|
+
);
|
|
951
|
+
}, SLOW);
|
|
952
|
+
|
|
953
|
+
it('keeps an entry a query word names by its whole name at its own rank', async () => {
|
|
954
|
+
// Two words join into TextInput, and TextArea also matches two words
|
|
955
|
+
// through its joined keyword; one word is still TextArea's whole name.
|
|
956
|
+
const {data} = await search('text input and textarea with multi line', {
|
|
957
|
+
cwd,
|
|
958
|
+
});
|
|
959
|
+
expect(data.results[0]).toMatchObject({name: 'TextArea'});
|
|
960
|
+
}, SLOW);
|
|
961
|
+
|
|
962
|
+
it('ranks a match on more of the query above a shorter named entry', async () => {
|
|
963
|
+
const {data} = await search('dropdown menu radio options', {cwd});
|
|
964
|
+
expect(data.results[0]).toMatchObject({name: 'DropdownMenuRadioItem'});
|
|
965
|
+
}, SLOW);
|
|
966
|
+
|
|
967
|
+
it('lets a plural start a name through its singular', () => {
|
|
968
|
+
expect(
|
|
969
|
+
scoreCandidate('tokens', {domain: 'component', name: 'Tokenizer'}),
|
|
970
|
+
).toMatchObject({score: 60});
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
it('finds Icon by a glyph name', async () => {
|
|
974
|
+
for (const q of ['cog', 'lightning bolt']) {
|
|
975
|
+
const {data} = await search(q, {cwd});
|
|
976
|
+
expect(data.results[0], q).toMatchObject({
|
|
977
|
+
domain: 'component',
|
|
978
|
+
name: 'Icon',
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
}, SLOW);
|
|
982
|
+
|
|
983
|
+
it('matches a verb form against its verb', () => {
|
|
984
|
+
// "spacing" lost the final e of "space".
|
|
985
|
+
expect(
|
|
986
|
+
scoreCandidate('spacing', {domain: 'component', name: 'Gap', keywords: ['space']}),
|
|
987
|
+
).toMatchObject({score: 88});
|
|
988
|
+
expect(
|
|
989
|
+
scoreCandidate('dragging', {domain: 'component', name: 'Gap', keywords: ['drag']}),
|
|
990
|
+
).toMatchObject({score: 88});
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
it('lets a plural start a longer word through its singular', () => {
|
|
994
|
+
expect(
|
|
995
|
+
scoreCandidate('chips', {domain: 'component', name: 'Chipset'}),
|
|
996
|
+
).toMatchObject({score: 60});
|
|
997
|
+
// A four-letter singular is too short: "stats" does not start "statusbar".
|
|
998
|
+
expect(
|
|
999
|
+
scoreCandidate('stats', {domain: 'component', name: 'Statusbar'}),
|
|
1000
|
+
).toBeNull();
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
it('leaves an identifier joined with _ unmatched when nothing has it', async () => {
|
|
1004
|
+
const {data} = await search('qqzz_no_match_here', {cwd});
|
|
1005
|
+
expect(data.results).toEqual([]);
|
|
1006
|
+
}, SLOW);
|
|
1007
|
+
});
|
|
@@ -30,7 +30,7 @@ export type SearchResultEntry = {
|
|
|
30
30
|
*/
|
|
31
31
|
description: string;
|
|
32
32
|
/**
|
|
33
|
-
* - Follow-up command to act on this result (e.g. `astryx component Button`, or `astryx theme add neutral` for a theme).
|
|
33
|
+
* - Follow-up command to act on this result (e.g. `astryx component Button`, or `astryx theme add neutral` for a theme; `astryx theme eject neutral` outside a project).
|
|
34
34
|
*/
|
|
35
35
|
command: string;
|
|
36
36
|
/**
|
|
@@ -72,6 +72,19 @@ export type SearchResponse = {
|
|
|
72
72
|
matchCount: number;
|
|
73
73
|
results: SearchResultEntry[];
|
|
74
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* -
|
|
77
|
+
* `partial`, when an open search could not get the Core that components,
|
|
78
|
+
* hooks, and templates are read from (such as outside a project, offline,
|
|
79
|
+
* before the release's Core was downloaded): the domains it skipped and why.
|
|
80
|
+
* The results are the docs and themes.
|
|
81
|
+
*/
|
|
82
|
+
meta?: {
|
|
83
|
+
partial?: {
|
|
84
|
+
skipped: SearchDomain[];
|
|
85
|
+
reason: string;
|
|
86
|
+
};
|
|
87
|
+
} | undefined;
|
|
75
88
|
};
|
|
76
89
|
/**
|
|
77
90
|
* Options for `search()`.
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* @property {number} score - Relevance score (higher is better).
|
|
21
21
|
* @property {string} reason - Human-readable reason the candidate matched (e.g. `keyword "button"`).
|
|
22
22
|
* @property {string} description - One-line description, when available.
|
|
23
|
-
* @property {string} command - Follow-up command to act on this result (e.g. `astryx component Button`, or `astryx theme add neutral` for a theme).
|
|
23
|
+
* @property {string} command - Follow-up command to act on this result (e.g. `astryx component Button`, or `astryx theme add neutral` for a theme; `astryx theme eject neutral` outside a project).
|
|
24
24
|
* @property {string} [import] - Import path — present for component and hook results.
|
|
25
25
|
* @property {string} [title] - Doc title — present for doc results.
|
|
26
26
|
* @property {string} [section] - Section key — present when a doc result is one section of a topic; `command` reads only that section.
|
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
* @property {string} data.query
|
|
39
39
|
* @property {number} data.matchCount - How many candidates matched the query in total, before `limit` was applied. `results` is the bounded slice of that set, so `matchCount > results.length` means the answer was capped.
|
|
40
40
|
* @property {SearchResultEntry[]} data.results
|
|
41
|
+
* @property {{partial?: {skipped: SearchDomain[], reason: string}}} [meta] -
|
|
42
|
+
* `partial`, when an open search could not get the Core that components,
|
|
43
|
+
* hooks, and templates are read from (such as outside a project, offline,
|
|
44
|
+
* before the release's Core was downloaded): the domains it skipped and why.
|
|
45
|
+
* The results are the docs and themes.
|
|
41
46
|
*/
|
|
42
47
|
|
|
43
48
|
/**
|
package/api/swizzle/_adapter.mjs
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* (ERR_CORE_NOT_FOUND) when core can't be located.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import {findProjectCoreDir, listComponents} from '../../foundation/fs/paths.mjs';
|
|
15
15
|
import {resolveComponentReplacements} from '../../foundation/discovery/component-replacement.mjs';
|
|
16
16
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
17
17
|
import {AstryxError} from '../error.mjs';
|
|
@@ -44,7 +44,7 @@ export async function resolveComponentReplacement(
|
|
|
44
44
|
* @returns {{coreDir: string, components: string[]}}
|
|
45
45
|
*/
|
|
46
46
|
export function resolveCore(cwd) {
|
|
47
|
-
const coreDir =
|
|
47
|
+
const coreDir = findProjectCoreDir(cwd);
|
|
48
48
|
if (!coreDir) {
|
|
49
49
|
throw new AstryxError(
|
|
50
50
|
'Could not find @astryxdesign/core package. Make sure you are inside the design system monorepo or have @astryxdesign/core installed.',
|
|
@@ -115,7 +115,7 @@ function buildFeedback(component, issuesUrl) {
|
|
|
115
115
|
*/
|
|
116
116
|
async function loadConfigSafely(cwd) {
|
|
117
117
|
try {
|
|
118
|
-
const project = await Project.load(cwd);
|
|
118
|
+
const project = await Project.load(cwd, {core: 'project'});
|
|
119
119
|
return {
|
|
120
120
|
loadedIntegrations: project.loadedIntegrations,
|
|
121
121
|
issuesUrl: project.config.issuesUrl,
|
|
@@ -736,7 +736,7 @@ describe('integration template discovery', () => {
|
|
|
736
736
|
const command = await runCli(['template', 'shell-side-nav'], tmpDir);
|
|
737
737
|
expect(command.status).toBe(0);
|
|
738
738
|
expect(command.stderr).toContain('@acme/extra has 1 integration issue');
|
|
739
|
-
expect(command.stderr).
|
|
739
|
+
expect(command.stderr).toMatch(/Run: .+ doctor/);
|
|
740
740
|
|
|
741
741
|
const doctor = await runCli(['doctor'], tmpDir);
|
|
742
742
|
expect(doctor.status).toBe(0);
|
package/api/theme/_adapter.d.mts
CHANGED
|
@@ -129,6 +129,22 @@ export function removeThemeFromApp(slug: string, options?: {
|
|
|
129
129
|
export function useThemeInApp(slug: string, options?: {
|
|
130
130
|
cwd?: string;
|
|
131
131
|
}): Promise<import("./theme.type.mjs").ThemeAppResponse>;
|
|
132
|
+
/**
|
|
133
|
+
* The Core theme targets are read from: the project's, else the release's
|
|
134
|
+
* own, installed into the per-user cache first when needed (a network install
|
|
135
|
+
* and an npm subprocess; spec AST-081 FR3). Throws as requireCoreDir does.
|
|
136
|
+
* @param {string} cwd
|
|
137
|
+
* @returns {string}
|
|
138
|
+
*/
|
|
139
|
+
export function requireThemeCoreDir(cwd: string): string;
|
|
140
|
+
/**
|
|
141
|
+
* The Core a theme build reads outside a project: the one the answering copy
|
|
142
|
+
* carries, installed into the per-user cache first when needed (a network
|
|
143
|
+
* install and an npm subprocess; spec AST-081 FR3); null when there is none.
|
|
144
|
+
* @param {string} cwd
|
|
145
|
+
* @returns {string | null}
|
|
146
|
+
*/
|
|
147
|
+
export function fetchCarriedThemeCoreDir(cwd: string): string | null;
|
|
132
148
|
/**
|
|
133
149
|
* A bundled theme entry kept for the historical public `listThemes()` helper.
|
|
134
150
|
*/
|
package/api/theme/_adapter.mjs
CHANGED
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
import * as fs from 'node:fs';
|
|
13
13
|
import * as path from 'node:path';
|
|
14
|
+
import {
|
|
15
|
+
findCarriedCoreDir,
|
|
16
|
+
requireCoreDir,
|
|
17
|
+
} from '../../foundation/fs/paths.mjs';
|
|
14
18
|
import {Project} from '../../foundation/config/project.mjs';
|
|
15
19
|
import {
|
|
16
20
|
BUNDLED_THEME_PACKAGE,
|
|
@@ -41,6 +45,7 @@ import {stripCopyrightHeader} from '../../foundation/text/copyright-header.mjs';
|
|
|
41
45
|
import {loadIntegrations} from '../../foundation/integrations/integrations.mjs';
|
|
42
46
|
import {importThemeArtifact} from '../../foundation/fs/module-loader.mjs';
|
|
43
47
|
import {applyWrites} from '../integration/add-helpers.mjs';
|
|
48
|
+
import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
|
|
44
49
|
|
|
45
50
|
export {BUNDLED_THEME_PACKAGE, THEMES_DIR};
|
|
46
51
|
|
|
@@ -565,7 +570,7 @@ export function resolveRecordedThemes(state, available) {
|
|
|
565
570
|
);
|
|
566
571
|
if (!theme) {
|
|
567
572
|
throw new AstryxError(
|
|
568
|
-
`Added theme "${slug}" from ${owner} is unavailable. Reinstall the package or restore the local theme, then run
|
|
573
|
+
`Added theme "${slug}" from ${owner} is unavailable. Reinstall the package or restore the local theme, then run \`${formatCliCommand(`theme add ${slug} --package ${owner}`, state.projectDir)}\`.`,
|
|
569
574
|
undefined,
|
|
570
575
|
ERROR_CODES.ERR_UNKNOWN_THEME,
|
|
571
576
|
);
|
|
@@ -732,14 +737,14 @@ export async function removeThemeFromApp(slug, options = {}) {
|
|
|
732
737
|
const recordedSlug = recordedThemeSlug(state, slug);
|
|
733
738
|
if (!state.configured || recordedSlug == null) {
|
|
734
739
|
throw new AstryxError(
|
|
735
|
-
`Theme "${slug}" is not added. Run
|
|
740
|
+
`Theme "${slug}" is not added. Run \`${formatCliCommand(`theme add ${slug}`, state.projectDir)}\` first.`,
|
|
736
741
|
undefined,
|
|
737
742
|
ERROR_CODES.ERR_UNKNOWN_THEME,
|
|
738
743
|
);
|
|
739
744
|
}
|
|
740
745
|
if (state.defaultSlug === recordedSlug) {
|
|
741
746
|
throw new AstryxError(
|
|
742
|
-
`Theme "${recordedSlug}" is the default. Run
|
|
747
|
+
`Theme "${recordedSlug}" is the default. Run \`${formatCliCommand('theme use <other-slug>', state.projectDir)}\` before removing it.`,
|
|
743
748
|
undefined,
|
|
744
749
|
ERROR_CODES.ERR_THEME_INVALID,
|
|
745
750
|
);
|
|
@@ -748,7 +753,7 @@ export async function removeThemeFromApp(slug, options = {}) {
|
|
|
748
753
|
delete themes[recordedSlug];
|
|
749
754
|
if (state.defaultSlug == null) {
|
|
750
755
|
throw new AstryxError(
|
|
751
|
-
|
|
756
|
+
`The generated theme module has no default theme. Run \`${formatCliCommand('theme use <slug>', state.projectDir)}\` first.`,
|
|
752
757
|
undefined,
|
|
753
758
|
ERROR_CODES.ERR_THEME_INVALID,
|
|
754
759
|
);
|
|
@@ -776,7 +781,7 @@ export async function useThemeInApp(slug, options = {}) {
|
|
|
776
781
|
const recordedSlug = recordedThemeSlug(state, slug);
|
|
777
782
|
if (!state.configured || recordedSlug == null) {
|
|
778
783
|
throw new AstryxError(
|
|
779
|
-
`Theme "${slug}" is not added. Run
|
|
784
|
+
`Theme "${slug}" is not added. Run \`${formatCliCommand(`theme add ${slug}`, state.projectDir)}\` first.`,
|
|
780
785
|
undefined,
|
|
781
786
|
ERROR_CODES.ERR_UNKNOWN_THEME,
|
|
782
787
|
);
|
|
@@ -792,3 +797,25 @@ export async function useThemeInApp(slug, options = {}) {
|
|
|
792
797
|
available,
|
|
793
798
|
);
|
|
794
799
|
}
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* The Core theme targets are read from: the project's, else the release's
|
|
803
|
+
* own, installed into the per-user cache first when needed (a network install
|
|
804
|
+
* and an npm subprocess; spec AST-081 FR3). Throws as requireCoreDir does.
|
|
805
|
+
* @param {string} cwd
|
|
806
|
+
* @returns {string}
|
|
807
|
+
*/
|
|
808
|
+
export function requireThemeCoreDir(cwd) {
|
|
809
|
+
return requireCoreDir(cwd);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* The Core a theme build reads outside a project: the one the answering copy
|
|
814
|
+
* carries, installed into the per-user cache first when needed (a network
|
|
815
|
+
* install and an npm subprocess; spec AST-081 FR3); null when there is none.
|
|
816
|
+
* @param {string} cwd
|
|
817
|
+
* @returns {string | null}
|
|
818
|
+
*/
|
|
819
|
+
export function fetchCarriedThemeCoreDir(cwd) {
|
|
820
|
+
return findCarriedCoreDir(cwd, {fetch: true});
|
|
821
|
+
}
|
|
@@ -110,13 +110,14 @@ export function themeBuildForReport(file: string, options?: {
|
|
|
110
110
|
receipt: import("../theme.type.mjs").ThemeBuildResponse | import("../theme.type.mjs").ThemeBuildCheckResponse | null;
|
|
111
111
|
trailer: ThemeBuildTrailer | null;
|
|
112
112
|
}>;
|
|
113
|
-
/** @param {string} file @param {{out?: string, check?: boolean, iconsSpecifier?: string}} [options] @param {{cwd?: string}} [ctx] @returns {Promise<import('../theme.type.mjs').ThemeBuildResponse | import('../theme.type.mjs').ThemeBuildCheckResponse | null>} */
|
|
113
|
+
/** @param {string} file @param {{out?: string, check?: boolean, iconsSpecifier?: string}} [options] @param {{cwd?: string, projectCore?: boolean}} [ctx] `projectCore`: read only the project's installed Core, never the carried one (doctor; spec AST-081 FR3) @returns {Promise<import('../theme.type.mjs').ThemeBuildResponse | import('../theme.type.mjs').ThemeBuildCheckResponse | null>} */
|
|
114
114
|
export function themeBuild(file: string, options?: {
|
|
115
115
|
out?: string;
|
|
116
116
|
check?: boolean;
|
|
117
117
|
iconsSpecifier?: string;
|
|
118
118
|
}, ctx?: {
|
|
119
119
|
cwd?: string;
|
|
120
|
+
projectCore?: boolean;
|
|
120
121
|
}): Promise<import("../theme.type.mjs").ThemeBuildResponse | import("../theme.type.mjs").ThemeBuildCheckResponse | null>;
|
|
121
122
|
/** @param {string[]} files @param {{familyKey: string, check?: boolean, iconsSpecifier?: string, __onPrivateVarError?: () => void}} options @param {{cwd?: string}} [ctx] */
|
|
122
123
|
export function themeBuildFamily(files: string[], options: {
|
|
@@ -70,7 +70,11 @@ import {
|
|
|
70
70
|
CLI_ROOT,
|
|
71
71
|
findCoreDir,
|
|
72
72
|
findInstalledPackage,
|
|
73
|
+
findProjectCoreDir,
|
|
73
74
|
} from '../../../foundation/fs/paths.mjs';
|
|
75
|
+
import {isGlobalCopy} from '../../../foundation/release/choose.mjs';
|
|
76
|
+
import {isInReleaseCache} from '../../../foundation/release/cache.mjs';
|
|
77
|
+
import {fetchCarriedThemeCoreDir} from '../_adapter.mjs';
|
|
74
78
|
import {
|
|
75
79
|
assertWithin,
|
|
76
80
|
sanitizeName,
|
|
@@ -306,10 +310,15 @@ function realLocation(target) {
|
|
|
306
310
|
*
|
|
307
311
|
* @param {string} cwd
|
|
308
312
|
* @param {CoreBindings} cliCore - The CLI's own Core, from {@link loadCliCore}.
|
|
313
|
+
* @param {{projectOnly?: boolean}} [options] `projectOnly`: never the
|
|
314
|
+
* carried Core, as for doctor (spec AST-081 FR3)
|
|
309
315
|
* @returns {Promise<CoreBindings | null>}
|
|
310
316
|
*/
|
|
311
|
-
async function loadProjectCore(cwd, cliCore) {
|
|
312
|
-
|
|
317
|
+
async function loadProjectCore(cwd, cliCore, {projectOnly = false} = {}) {
|
|
318
|
+
// Outside a project, the Core the answering copy carries (spec AST-081 FR3).
|
|
319
|
+
const dir =
|
|
320
|
+
findInstalledPackage(cwd, '@astryxdesign/core') ??
|
|
321
|
+
(projectOnly ? null : fetchCarriedThemeCoreDir(cwd));
|
|
313
322
|
const themeFile = dir ? importTarget(dir, './theme') : null;
|
|
314
323
|
if (!dir || !themeFile) return null;
|
|
315
324
|
if (cliCore.themeModule) {
|
|
@@ -355,14 +364,54 @@ const _projectCores = new Map();
|
|
|
355
364
|
|
|
356
365
|
/**
|
|
357
366
|
* Choose the Core this build generates with: the project's installed one when
|
|
358
|
-
* {@link loadProjectCore} finds it, else the CLI's own.
|
|
367
|
+
* {@link loadProjectCore} finds it, else the CLI's own. With `projectOnly`,
|
|
368
|
+
* only the project's installed Core: a build that cannot use it fails rather
|
|
369
|
+
* than read the Core the answering copy carries (spec AST-081 FR3).
|
|
359
370
|
* @param {string} cwd
|
|
371
|
+
* @param {{projectOnly?: boolean}} [options]
|
|
360
372
|
*/
|
|
361
|
-
async function selectCore(cwd) {
|
|
373
|
+
async function selectCore(cwd, {projectOnly = false} = {}) {
|
|
362
374
|
const cliCore = await loadCliCore();
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
375
|
+
const key = `${projectOnly ? 'project' : 'any'}\0${cwd}`;
|
|
376
|
+
if (!_projectCores.has(key))
|
|
377
|
+
_projectCores.set(key, await loadProjectCore(cwd, cliCore, {projectOnly}));
|
|
378
|
+
const projectCore = _projectCores.get(key);
|
|
379
|
+
// A global or cached copy's own Core is the carried one.
|
|
380
|
+
if (projectOnly && !projectCore && carriesCore() && !cliCoreIsProjects(cwd)) {
|
|
381
|
+
throw new AstryxError(
|
|
382
|
+
"The project's Core isn't installed or does not load.",
|
|
383
|
+
undefined,
|
|
384
|
+
ERROR_CODES.ERR_CORE_NOT_FOUND,
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
setCore(projectCore ?? cliCore);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Whether this CLI copy is one installed for the computer or kept in the
|
|
392
|
+
* per-user release cache, whose own Core import is the carried Core.
|
|
393
|
+
* @returns {boolean}
|
|
394
|
+
*/
|
|
395
|
+
function carriesCore() {
|
|
396
|
+
return isGlobalCopy(CLI_ROOT) || isInReleaseCache(CLI_ROOT);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Whether the Core the CLI's own import loads is the one the project at
|
|
401
|
+
* `cwd` installed.
|
|
402
|
+
* @param {string} cwd
|
|
403
|
+
* @returns {boolean}
|
|
404
|
+
*/
|
|
405
|
+
function cliCoreIsProjects(cwd) {
|
|
406
|
+
const dir = findProjectCoreDir(cwd);
|
|
407
|
+
if (!dir) return false;
|
|
408
|
+
try {
|
|
409
|
+
const own = fileURLToPath(import.meta.resolve('@astryxdesign/core/theme'));
|
|
410
|
+
const theirs = importTarget(dir, './theme');
|
|
411
|
+
return theirs != null && realOrSelf(own) === realOrSelf(theirs);
|
|
412
|
+
} catch {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
366
415
|
}
|
|
367
416
|
|
|
368
417
|
/**
|
|
@@ -401,8 +450,7 @@ function inAstryxRepository(cwd) {
|
|
|
401
450
|
* @returns {string}
|
|
402
451
|
*/
|
|
403
452
|
export function coreUnavailableMessage(cwd, importError) {
|
|
404
|
-
const why =
|
|
405
|
-
'`astryx theme build` generates CSS with @astryxdesign/core, the same code the runtime <Theme> uses';
|
|
453
|
+
const why = `\`${formatCliCommand('theme build')}\` generates CSS with @astryxdesign/core, the same code the runtime <Theme> uses`;
|
|
406
454
|
const detail = importError ? `\n Import error: ${importError.message}` : '';
|
|
407
455
|
if (inAstryxRepository(cwd)) {
|
|
408
456
|
return (
|
|
@@ -2497,13 +2545,14 @@ function validateHeadingTypeAugmentationSupport(themeDef) {
|
|
|
2497
2545
|
* output must stay inside, for a CLI-internal scratch build. `iconsSpecifier` overrides the icon registry import
|
|
2498
2546
|
* specifier in the generated module (e.g. `./icons.mjs`); when omitted, the
|
|
2499
2547
|
* direct registry specifiers from the theme source are emitted unchanged.
|
|
2500
|
-
* @param {{cwd?: string}} [ctx]
|
|
2548
|
+
* @param {{cwd?: string, projectCore?: boolean}} [ctx] `projectCore`: only the
|
|
2549
|
+
* project's installed Core (spec AST-081 FR3)
|
|
2501
2550
|
* @returns {Promise<any>}
|
|
2502
2551
|
*/
|
|
2503
2552
|
async function themeBuildInternal(
|
|
2504
2553
|
file,
|
|
2505
2554
|
options = {},
|
|
2506
|
-
{cwd = process.cwd()} = {},
|
|
2555
|
+
{cwd = process.cwd(), projectCore = false} = {},
|
|
2507
2556
|
/** @type {{compact?: boolean, trailers?: ThemeBuildTrailer[]}} */ report = {},
|
|
2508
2557
|
) {
|
|
2509
2558
|
const filePath = path.resolve(cwd, file);
|
|
@@ -2522,7 +2571,14 @@ async function themeBuildInternal(
|
|
|
2522
2571
|
// A compact report has no per-theme heading, so each warning names its file.
|
|
2523
2572
|
const source = report.compact ? `${path.relative(cwd, filePath)}: ` : '';
|
|
2524
2573
|
|
|
2525
|
-
|
|
2574
|
+
if (projectCore && !findProjectCoreDir(cwd)) {
|
|
2575
|
+
throw new AstryxError(
|
|
2576
|
+
"The project's Core isn't installed.",
|
|
2577
|
+
undefined,
|
|
2578
|
+
ERROR_CODES.ERR_CORE_NOT_FOUND,
|
|
2579
|
+
);
|
|
2580
|
+
}
|
|
2581
|
+
await selectCore(cwd, {projectOnly: projectCore});
|
|
2526
2582
|
|
|
2527
2583
|
// Standalone builds only need interception when an older Core could erase
|
|
2528
2584
|
// adaptations. Family preparation always supplies the same recorder as its
|
|
@@ -3272,7 +3328,7 @@ export function printCompactTrailer(trailers, {hint = false} = {}) {
|
|
|
3272
3328
|
)
|
|
3273
3329
|
.join(', ');
|
|
3274
3330
|
logger.log(
|
|
3275
|
-
`[note] Fonts named but not loaded: ${named}. Load them in your app (recipe:
|
|
3331
|
+
`[note] Fonts named but not loaded: ${named}. Load them in your app (recipe: ${formatCliCommand('docs typography')}).`,
|
|
3276
3332
|
);
|
|
3277
3333
|
}
|
|
3278
3334
|
if (hint) {
|
|
@@ -3327,7 +3383,7 @@ export async function themeBuildForReport(
|
|
|
3327
3383
|
return {receipt, trailer: trailers[0] ?? null};
|
|
3328
3384
|
}
|
|
3329
3385
|
|
|
3330
|
-
/** @param {string} file @param {{out?: string, check?: boolean, iconsSpecifier?: string}} [options] @param {{cwd?: string}} [ctx] @returns {Promise<import('../theme.type.mjs').ThemeBuildResponse | import('../theme.type.mjs').ThemeBuildCheckResponse | null>} */
|
|
3386
|
+
/** @param {string} file @param {{out?: string, check?: boolean, iconsSpecifier?: string}} [options] @param {{cwd?: string, projectCore?: boolean}} [ctx] `projectCore`: read only the project's installed Core, never the carried one (doctor; spec AST-081 FR3) @returns {Promise<import('../theme.type.mjs').ThemeBuildResponse | import('../theme.type.mjs').ThemeBuildCheckResponse | null>} */
|
|
3331
3387
|
export async function themeBuild(file, options = {}, ctx = {}) {
|
|
3332
3388
|
return /** @type {any} */ (themeBuildInternal(file, options, ctx));
|
|
3333
3389
|
}
|
|
@@ -37,6 +37,7 @@ import * as path from 'node:path';
|
|
|
37
37
|
import {fileURLToPath} from 'node:url';
|
|
38
38
|
|
|
39
39
|
import {findInstalledPackage} from '../../../foundation/fs/paths.mjs';
|
|
40
|
+
import {CLI_VERSION} from '../../../test-utils/release-fixtures.mjs';
|
|
40
41
|
|
|
41
42
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
42
43
|
const REPO_ROOT = path.resolve(HERE, '../../../../..');
|
|
@@ -55,8 +56,12 @@ const RUNTIME_DEPS = [
|
|
|
55
56
|
'zod',
|
|
56
57
|
];
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
// Both Cores carry the packed CLI's own version: a run through the bin in a
|
|
60
|
+
// project whose Core is another release is handed to that release (spec
|
|
61
|
+
// AST-081 FR2), so the old surface is told apart by what it exports, not by
|
|
62
|
+
// its version.
|
|
63
|
+
const OLD_CORE_VERSION = CLI_VERSION;
|
|
64
|
+
const CURRENT_CORE_VERSION = CLI_VERSION;
|
|
60
65
|
const TSC_BIN = path.join(REPO_ROOT, 'node_modules/typescript/bin/tsc');
|
|
61
66
|
|
|
62
67
|
/**
|
|
@@ -278,8 +283,20 @@ function buildTheme(themeFile, extraArgs = []) {
|
|
|
278
283
|
'node_modules/@astryxdesign/cli/clients/cli/bin/astryx.mjs',
|
|
279
284
|
);
|
|
280
285
|
try {
|
|
286
|
+
// A packed CLI outside any project's package.json reads as installed for
|
|
287
|
+
// the computer, so it gets a home folder of its own: nothing it keeps for
|
|
288
|
+
// the computer lands in the real one.
|
|
289
|
+
const home = path.join(root, 'home');
|
|
290
|
+
const env = {
|
|
291
|
+
...process.env,
|
|
292
|
+
HOME: home,
|
|
293
|
+
USERPROFILE: home,
|
|
294
|
+
XDG_CONFIG_HOME: path.join(home, '.config'),
|
|
295
|
+
XDG_CACHE_HOME: path.join(home, '.cache'),
|
|
296
|
+
NO_UPDATE_NOTIFIER: '1',
|
|
297
|
+
};
|
|
281
298
|
// prettier-ignore
|
|
282
|
-
const stdout = execFileSync(process.execPath, [bin, 'theme', 'build', ...(Array.isArray(themeFile) ? themeFile : [themeFile]), ...extraArgs, '--json'], {cwd: consumer, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe']});
|
|
299
|
+
const stdout = execFileSync(process.execPath, [bin, 'theme', 'build', ...(Array.isArray(themeFile) ? themeFile : [themeFile]), ...extraArgs, '--json'], {cwd: consumer, encoding: 'utf8', env, stdio: ['ignore', 'pipe', 'pipe']});
|
|
283
300
|
return {status: 0, envelope: JSON.parse(stdout)};
|
|
284
301
|
} catch (error) {
|
|
285
302
|
const e = /** @type {any} */ (error);
|
|
@@ -21,9 +21,11 @@
|
|
|
21
21
|
* @output Ordered, case-insensitively deduped family names, and the human
|
|
22
22
|
* help snippet (<link> pair + @font-face) printed after the install
|
|
23
23
|
* instructions.
|
|
24
|
-
* @position Sits beside build.mjs (api/theme/build/). Pure functions, no IO
|
|
25
|
-
*
|
|
24
|
+
* @position Sits beside build.mjs (api/theme/build/). Pure functions, no IO
|
|
25
|
+
* beyond the CLI invocation the human help names (formatCliCommand), so the
|
|
26
|
+
* `--json` receipt and the human output share one source of truth.
|
|
26
27
|
*/
|
|
28
|
+
import {formatCliCommand} from '../../../foundation/env/package-manager.mjs';
|
|
27
29
|
|
|
28
30
|
// font-family values that never need loading: CSS generic families, the ui-*
|
|
29
31
|
// system keywords, and CSS-wide keywords that can appear in a token value.
|
|
@@ -254,6 +256,6 @@ function fontLoadingRecipe(families) {
|
|
|
254
256
|
font-display: swap;
|
|
255
257
|
}
|
|
256
258
|
|
|
257
|
-
Recipe and fallback-stack guidance:
|
|
259
|
+
Recipe and fallback-stack guidance: ${formatCliCommand('docs typography')}
|
|
258
260
|
`;
|
|
259
261
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import {describe, it, expect} from 'vitest';
|
|
17
17
|
import {collectUnloadedFonts, formatFontLoadingHelp} from './font-warning.mjs';
|
|
18
|
+
import {formatCliCommand} from '../../../foundation/env/package-manager.mjs';
|
|
18
19
|
|
|
19
20
|
describe('collectUnloadedFonts', () => {
|
|
20
21
|
it('returns webfont families from font-family tokens, skipping known fallbacks', () => {
|
|
@@ -255,7 +256,7 @@ describe('formatFontLoadingHelp', () => {
|
|
|
255
256
|
});
|
|
256
257
|
|
|
257
258
|
it('points at the docs recipe', () => {
|
|
258
|
-
expect(help).toContain('
|
|
259
|
+
expect(help).toContain(formatCliCommand('docs typography'));
|
|
259
260
|
});
|
|
260
261
|
|
|
261
262
|
it('percent-encodes family names in the css2 URL', () => {
|
|
@@ -81,14 +81,14 @@ describe('themeRemove', () => {
|
|
|
81
81
|
it('refuses to remove the default and names theme use', async () => {
|
|
82
82
|
await expect(themeRemove('ocean', {cwd: tmpDir})).rejects.toMatchObject({
|
|
83
83
|
code: 'ERR_THEME_INVALID',
|
|
84
|
-
message: expect.stringContaining('
|
|
84
|
+
message: expect.stringContaining(' theme use <other-slug>`'),
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
it('names theme add when the slug is not added', async () => {
|
|
89
89
|
await expect(themeRemove('missing', {cwd: tmpDir})).rejects.toMatchObject({
|
|
90
90
|
code: 'ERR_UNKNOWN_THEME',
|
|
91
|
-
message: expect.stringContaining('
|
|
91
|
+
message: expect.stringContaining(' theme add missing`'),
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
94
|
});
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import * as path from 'node:path';
|
|
15
|
-
import {
|
|
15
|
+
import {requireThemeCoreDir} from '../_adapter.mjs';
|
|
16
16
|
import {collectThemingTargets} from '../../../foundation/discovery/theming-targets.mjs';
|
|
17
17
|
import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
|
|
18
|
-
import {AstryxError} from '../../error.mjs';
|
|
18
|
+
import {AstryxError, coreDirOrThrow} from '../../error.mjs';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Whether a target matches the caller's filter loosely: any target whose key,
|
|
@@ -46,14 +46,7 @@ function matchesLoosely(target, filter) {
|
|
|
46
46
|
* @returns {Promise<import('../theme.type.mjs').ThemeTargetsResponse>}
|
|
47
47
|
*/
|
|
48
48
|
export async function themeTargets(filter, {cwd = process.cwd()} = {}) {
|
|
49
|
-
const coreDir =
|
|
50
|
-
if (!coreDir) {
|
|
51
|
-
throw new AstryxError(
|
|
52
|
-
'Could not find @astryxdesign/core package',
|
|
53
|
-
undefined,
|
|
54
|
-
ERROR_CODES.ERR_CORE_NOT_FOUND,
|
|
55
|
-
);
|
|
56
|
-
}
|
|
49
|
+
const coreDir = coreDirOrThrow(requireThemeCoreDir, cwd);
|
|
57
50
|
|
|
58
51
|
const all = await collectThemingTargets(path.join(coreDir, 'src'));
|
|
59
52
|
const needle = filter ? String(filter).toLowerCase() : null;
|