@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
|
@@ -80,6 +80,28 @@ describe('validate-integration API', () => {
|
|
|
80
80
|
expect(errors).toBe(0);
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
+
it('warns, with a fix and the file, on docs no reader can serve', async () => {
|
|
84
|
+
const pkgDir = path.join(tmpDir, 'pkg');
|
|
85
|
+
writePackage(pkgDir, {
|
|
86
|
+
manifest: `export default { docs: './docs' };\n`,
|
|
87
|
+
});
|
|
88
|
+
fs.mkdirSync(path.join(pkgDir, 'docs'), {recursive: true});
|
|
89
|
+
fs.writeFileSync(
|
|
90
|
+
path.join(pkgDir, 'docs', 'ghost.doc.zh.mjs'),
|
|
91
|
+
"export default {title: 'ghost'};\n",
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const result = await validateLocalIntegration(pkgDir);
|
|
95
|
+
|
|
96
|
+
expect(byCode(result.issues, 'orphan_doc_overlay')).toEqual([
|
|
97
|
+
expect.objectContaining({
|
|
98
|
+
severity: 'warning',
|
|
99
|
+
file: 'docs/ghost.doc.zh.mjs',
|
|
100
|
+
fix: expect.stringContaining('Delete docs/ghost.doc.zh.mjs'),
|
|
101
|
+
}),
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
|
|
83
105
|
it('reports an unknown manifest key as a warning, and still loads the rest', async () => {
|
|
84
106
|
// The manifest used to be parsed with a strict schema, so a single unknown
|
|
85
107
|
// key failed the parse — and an integration whose manifest fails to parse
|
|
@@ -321,6 +343,36 @@ export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description:
|
|
|
321
343
|
);
|
|
322
344
|
});
|
|
323
345
|
|
|
346
|
+
it('warns when a template source has no same-stem metadata, skipping test files', async () => {
|
|
347
|
+
const pkgDir = path.join(tmpDir, 'pkg');
|
|
348
|
+
writePackage(pkgDir, {
|
|
349
|
+
manifest: `export default { templates: './templates' };\n`,
|
|
350
|
+
});
|
|
351
|
+
fs.mkdirSync(path.join(pkgDir, 'templates'));
|
|
352
|
+
fs.writeFileSync(
|
|
353
|
+
path.join(pkgDir, 'templates', 'stray.tsx'),
|
|
354
|
+
'export default function Stray() { return null; }\n',
|
|
355
|
+
);
|
|
356
|
+
fs.writeFileSync(
|
|
357
|
+
path.join(pkgDir, 'templates', 'stray.test.tsx'),
|
|
358
|
+
"import {it} from 'vitest';\nit('renders', () => {});\n",
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
const result = await validateLocalIntegration(pkgDir);
|
|
362
|
+
|
|
363
|
+
const warnings = byCode(result.issues, 'source_without_template_doc');
|
|
364
|
+
expect(warnings).toEqual([
|
|
365
|
+
expect.objectContaining({
|
|
366
|
+
severity: 'warning',
|
|
367
|
+
message: expect.stringContaining('"stray.tsx"'),
|
|
368
|
+
}),
|
|
369
|
+
]);
|
|
370
|
+
expect(warnings[0].message).not.toContain('stray.test.tsx');
|
|
371
|
+
expect(warnings[0].message).toContain(
|
|
372
|
+
"Fix: add stray.doc.mjs beside it with type: 'page' or 'block'",
|
|
373
|
+
);
|
|
374
|
+
});
|
|
375
|
+
|
|
324
376
|
it('reports codemods outside semver folders and invalid folder names', async () => {
|
|
325
377
|
const pkgDir = path.join(tmpDir, 'pkg');
|
|
326
378
|
writePackage(pkgDir, {
|
|
@@ -593,7 +645,10 @@ describe('integration diagnostics are read-only', () => {
|
|
|
593
645
|
'components/Orphan.doc.mjs',
|
|
594
646
|
"export default {type: 'component', name: 'Orphan', props: []};\n",
|
|
595
647
|
);
|
|
596
|
-
write(
|
|
648
|
+
write(
|
|
649
|
+
'templates/dash.doc.mjs',
|
|
650
|
+
"export default {type: 'page', name: 'Dash'};\n",
|
|
651
|
+
);
|
|
597
652
|
write(
|
|
598
653
|
'docs/theme.doc.mjs',
|
|
599
654
|
"export default {type: 'generic', name: 'theme', title: 'Theme', description: 'x', sections: [{title: 'A', content: [{type: 'prose', text: 'x'}]}]};\n",
|
|
@@ -614,7 +669,9 @@ describe('integration diagnostics are read-only', () => {
|
|
|
614
669
|
path.join(consumer, 'package.json'),
|
|
615
670
|
JSON.stringify({name: 'consumer'}),
|
|
616
671
|
);
|
|
617
|
-
writeDiagnosedPackage(
|
|
672
|
+
writeDiagnosedPackage(
|
|
673
|
+
path.join(consumer, 'node_modules', '@acme', 'widgets'),
|
|
674
|
+
);
|
|
618
675
|
const before = {pkg: snapshot(pkgDir), consumer: snapshot(consumer)};
|
|
619
676
|
|
|
620
677
|
const local = await validateIntegration(undefined, {cwd: pkgDir});
|
|
@@ -631,9 +688,13 @@ describe('integration diagnostics are read-only', () => {
|
|
|
631
688
|
}
|
|
632
689
|
|
|
633
690
|
expect(summarizeIssues(local.data.issues).errors).toBeGreaterThan(0);
|
|
634
|
-
expect(byCode(local.data.issues, 'unreachable_contribution')).toHaveLength(
|
|
691
|
+
expect(byCode(local.data.issues, 'unreachable_contribution')).toHaveLength(
|
|
692
|
+
1,
|
|
693
|
+
);
|
|
635
694
|
expect(summarizeIssues(installed.data.issues).errors).toBeGreaterThan(0);
|
|
636
|
-
expect({pkg: snapshot(pkgDir), consumer: snapshot(consumer)}).toEqual(
|
|
695
|
+
expect({pkg: snapshot(pkgDir), consumer: snapshot(consumer)}).toEqual(
|
|
696
|
+
before,
|
|
697
|
+
);
|
|
637
698
|
});
|
|
638
699
|
});
|
|
639
700
|
|
|
@@ -655,7 +716,9 @@ describe('validated separates "checked and clean" from "never checked"', () => {
|
|
|
655
716
|
expect(validate.data.issues).toEqual([]);
|
|
656
717
|
|
|
657
718
|
const templates = await integrationTemplateConflicts(undefined, {cwd: dir});
|
|
658
|
-
const components = await integrationComponentConflicts(undefined, {
|
|
719
|
+
const components = await integrationComponentConflicts(undefined, {
|
|
720
|
+
cwd: dir,
|
|
721
|
+
});
|
|
659
722
|
const docs = await integrationDocConflicts(undefined, {cwd: dir});
|
|
660
723
|
expect(templates.data.validated).toBe(false);
|
|
661
724
|
expect(components.data.validated).toBe(false);
|
|
@@ -671,7 +734,9 @@ describe('validated separates "checked and clean" from "never checked"', () => {
|
|
|
671
734
|
expect(validate.data.name).toBe('@acme/widgets');
|
|
672
735
|
|
|
673
736
|
const templates = await integrationTemplateConflicts(undefined, {cwd: dir});
|
|
674
|
-
const components = await integrationComponentConflicts(undefined, {
|
|
737
|
+
const components = await integrationComponentConflicts(undefined, {
|
|
738
|
+
cwd: dir,
|
|
739
|
+
});
|
|
675
740
|
const docs = await integrationDocConflicts(undefined, {cwd: dir});
|
|
676
741
|
expect(templates.data.validated).toBe(true);
|
|
677
742
|
expect(components.data.validated).toBe(true);
|
|
@@ -743,8 +808,12 @@ describe('unreadable folders are reported, never fatal', () => {
|
|
|
743
808
|
expect(
|
|
744
809
|
byCode(result.issues, 'unreadable_root').map(issue => issue.message),
|
|
745
810
|
).toEqual([
|
|
746
|
-
expect.stringMatching(
|
|
747
|
-
|
|
811
|
+
expect.stringMatching(
|
|
812
|
+
/^Declared codemods root cannot be read \(EACCES\)/,
|
|
813
|
+
),
|
|
814
|
+
expect.stringMatching(
|
|
815
|
+
/^Declared themes root cannot be read \(EACCES\)/,
|
|
816
|
+
),
|
|
748
817
|
]);
|
|
749
818
|
},
|
|
750
819
|
);
|
|
@@ -34,11 +34,19 @@ export type ValidateIntegrationOptions = {
|
|
|
34
34
|
*/
|
|
35
35
|
export type ValidateIntegrationResponse = {
|
|
36
36
|
type: "integration.validate";
|
|
37
|
+
/**
|
|
38
|
+
* `notes`: information beside the issues that fails nothing, such as
|
|
39
|
+
* `invalid_cli_command`, a `cliCommand` that was ignored as malformed
|
|
40
|
+
*/
|
|
37
41
|
data: {
|
|
38
42
|
validated: boolean;
|
|
39
43
|
name: string | null;
|
|
40
44
|
version: string | null;
|
|
41
45
|
issues: import("../../foundation/integrations/issue").AstryxIntegrationIssue[];
|
|
46
|
+
notes?: Array<{
|
|
47
|
+
code: string;
|
|
48
|
+
message: string;
|
|
49
|
+
}>;
|
|
42
50
|
docTypes?: DocTypesReport;
|
|
43
51
|
};
|
|
44
52
|
};
|
|
@@ -38,7 +38,9 @@
|
|
|
38
38
|
* "healthy" — the two are otherwise byte-identical.
|
|
39
39
|
* @typedef {object} ValidateIntegrationResponse
|
|
40
40
|
* @property {'integration.validate'} type
|
|
41
|
-
* @property {{validated: boolean, name: string | null, version: string | null, issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[], docTypes?: DocTypesReport}} data
|
|
41
|
+
* @property {{validated: boolean, name: string | null, version: string | null, issues: import('../../foundation/integrations/issue').AstryxIntegrationIssue[], notes?: Array<{code: string, message: string}>, docTypes?: DocTypesReport}} data
|
|
42
|
+
* `notes`: information beside the issues that fails nothing, such as
|
|
43
|
+
* `invalid_cli_command`, a `cliCommand` that was ignored as malformed
|
|
42
44
|
*/
|
|
43
45
|
|
|
44
46
|
/**
|
|
@@ -15,6 +15,7 @@ import * as fs from 'node:fs';
|
|
|
15
15
|
import * as path from 'node:path';
|
|
16
16
|
import {validateLocalIntegration} from './validate-integration.mjs';
|
|
17
17
|
import {integrationAddTheme} from './add-theme.mjs';
|
|
18
|
+
import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
|
|
18
19
|
|
|
19
20
|
let tmpDir;
|
|
20
21
|
|
|
@@ -76,8 +77,8 @@ describe('unread theme folders', () => {
|
|
|
76
77
|
]);
|
|
77
78
|
expect(issues.map(issue => issue.message)).toEqual([
|
|
78
79
|
'Folder "themes/Tide_Pool/" holds modules but no <name>Theme source or .doc.mjs descriptor, so Astryx does not read it as a theme. Fix: rename it to .Tide_Pool so Astryx skips it; a theme folder needs a lower-kebab name.',
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
`Folder "themes/reef/" holds modules but no <name>Theme source or .doc.mjs descriptor, so Astryx does not read it as a theme. Fix: if it is a theme, add reefTheme.ts and reefTheme.doc.mjs to it (\`${formatCliCommand('integration add theme reef', tmpDir)}\` writes both) and move its code into reefTheme.ts; if not, rename it to .reef so Astryx skips it.`,
|
|
81
|
+
`Folder "themes/sand/" holds modules but no <name>Theme source or .doc.mjs descriptor, so Astryx does not read it as a theme. Fix: if it is a theme, add sandTheme.ts and sandTheme.doc.mjs to it (\`${formatCliCommand('integration add theme sand', tmpDir)}\` writes both) and move its code into sandTheme.ts; if not, rename it to .sand so Astryx skips it.`,
|
|
81
82
|
]);
|
|
82
83
|
});
|
|
83
84
|
|
|
@@ -26,7 +26,9 @@ export const doc = {
|
|
|
26
26
|
'can stay exit-0 in a non-integration directory. It also checks every doc the ' +
|
|
27
27
|
'package ships under its roots (component, template, docs topic, theme, and translation, served or not) against ' +
|
|
28
28
|
"the published authoring type for its kind, as `tsc` would, with the project's " +
|
|
29
|
-
'own `typescript
|
|
29
|
+
'own `typescript` (or, where `typescript` is missing or has no JavaScript compiler ' +
|
|
30
|
+
'API, as TypeScript 7 does, the `@typescript/typescript6` it installs): an unknown ' +
|
|
31
|
+
'field, a missing required field, or a value outside ' +
|
|
30
32
|
"a field's type is a warning in `docTypes` naming the field and a fix. A test " +
|
|
31
33
|
'fixture under `__tests__` in the components or docs root is counted, not checked. ' +
|
|
32
34
|
'Without TypeScript, `docTypes` is `skipped` with a reason.',
|
|
@@ -60,7 +62,7 @@ export const doc = {
|
|
|
60
62
|
{
|
|
61
63
|
type: 'integration.validate',
|
|
62
64
|
description:
|
|
63
|
-
'The result envelope: `data.validated`, false when nothing was validated — with no `package.json` at all, `data.issues` carries one `no_package` error-severity issue so the command exits 1; with a `package.json` but no integration manifest, `data.issues` is empty, which means "not looked at", not "healthy"; `data.name` and `data.version` of the validated package (both null when `data.validated` is false; `data.name` is `(local package)` when the local package.json has no readable name), plus `data.issues`, an AstryxIntegrationIssue[] of {code, severity: `warning` | `error`, message}. When the manifest loads, `data.docTypes` holds the doc type check: `status` (`checked` | `skipped`), `reason` when skipped, `typescript`, `docs` (doc values checked), `findings` ({doc, line, export, type, field, problem: `unknown_field` | `missing_field` | `wrong_type`, severity: `warning`, message, fix}), `unchecked` ({doc, reason}: a doc that could not be fully checked, or a root its reader cannot read), and `fixtures` when the components or docs root holds test fixture docs under `__tests__`: how many, none of them checked.',
|
|
65
|
+
'The result envelope: `data.validated`, false when nothing was validated — with no `package.json` at all, `data.issues` carries one `no_package` error-severity issue so the command exits 1; with a `package.json` but no integration manifest, `data.issues` is empty, which means "not looked at", not "healthy"; `data.name` and `data.version` of the validated package (both null when `data.validated` is false; `data.name` is `(local package)` when the local package.json has no readable name), plus `data.issues`, an AstryxIntegrationIssue[] of {code, severity: `warning` | `error`, message, fix?, file?, line?}: `fix` is the change that resolves the issue, and `file` and `line` where it is, relative to the package, when the check knows them; and `data.notes` when there are any: {code, message} information that fails nothing, such as `invalid_cli_command` for a `cliCommand` that was ignored as malformed. When the manifest loads, `data.docTypes` holds the doc type check: `status` (`checked` | `skipped`), `reason` when skipped, `typescript`, `docs` (doc values checked), `findings` ({doc, line, export, type, field, problem: `unknown_field` | `missing_field` | `wrong_type`, severity: `warning`, message, fix}), `unchecked` ({doc, reason}: a doc that could not be fully checked, or a root its reader cannot read), and `fixtures` when the components or docs root holds test fixture docs under `__tests__`: how many, none of them checked.',
|
|
64
66
|
},
|
|
65
67
|
],
|
|
66
68
|
examples: [
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The Core a typed search reads: the project's, else the release's own,
|
|
6
|
+
* installed into the per-user cache first when needed. Throws as
|
|
7
|
+
* requireCoreDir does.
|
|
8
|
+
* @param {string} cwd
|
|
9
|
+
* @returns {string}
|
|
10
|
+
*/
|
|
11
|
+
export function requireSearchCoreDir(cwd: string): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Environment adapter for search: locating the Core a search reads,
|
|
5
|
+
* including the network install and npm subprocess that fetch a release's
|
|
6
|
+
* own Core outside a project (spec AST-081 FR3; architecture:cli-surface
|
|
7
|
+
* INV21).
|
|
8
|
+
*
|
|
9
|
+
* @input the folder a search runs in
|
|
10
|
+
* @output the Core folder a search reads
|
|
11
|
+
* @position packages/cli/api/search — imported by search.mjs only
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {requireCoreDir} from '../../foundation/fs/paths.mjs';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The Core a typed search reads: the project's, else the release's own,
|
|
18
|
+
* installed into the per-user cache first when needed. Throws as
|
|
19
|
+
* requireCoreDir does.
|
|
20
|
+
* @param {string} cwd
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
export function requireSearchCoreDir(cwd) {
|
|
24
|
+
return requireCoreDir(cwd);
|
|
25
|
+
}
|
package/api/search/search.d.mts
CHANGED
|
@@ -16,6 +16,48 @@ export function stem(w: string): string;
|
|
|
16
16
|
* @returns {boolean}
|
|
17
17
|
*/
|
|
18
18
|
export function sameWord(a: string, b: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* A query with its camelCase and PascalCase identifiers spelled as words, so
|
|
21
|
+
* `SidebarToggle` reads "sidebar toggle" and `useTablePaginationState` "use
|
|
22
|
+
* table pagination state". Plain words, and identifiers joined with `_` or `-`, are
|
|
23
|
+
* unchanged: a joined token that matches nothing stays unmatched.
|
|
24
|
+
* @param {string} query - The query as typed, before lowercasing.
|
|
25
|
+
* @returns {string} Lowercased.
|
|
26
|
+
*/
|
|
27
|
+
export function spellIdentifiers(query: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* The strongest hit a run of two or more adjacent query words has when it is
|
|
30
|
+
* read as one joined word, and the query words it covers. Readers type a
|
|
31
|
+
* compound name as separate words (`table header cell` is TableHeaderCell,
|
|
32
|
+
* `number field` the keyword `numberfield`), and no single word of the run
|
|
33
|
+
* matches on its own.
|
|
34
|
+
*
|
|
35
|
+
* - 100: the run joins to a component, hook, or template name, or its plural
|
|
36
|
+
* (`table header cells` is TableHeaderCell), or a hook name without its
|
|
37
|
+
* `use` prefix (`table sticky columns` is useTableStickyColumns).
|
|
38
|
+
* - 90: the run joins to a one-word keyword (`number field` is
|
|
39
|
+
* `numberfield`).
|
|
40
|
+
* - 95: the run joins to most of a name, cut short (`dropdown menu radio` is
|
|
41
|
+
* DropdownMenuRadioItem); 92: it is a name's leading words, covering at least half
|
|
42
|
+
* of it (`top nav mega` is TopNavMegaMenu); 70: it is two or more adjacent
|
|
43
|
+
* words of a name that cover at least half of it (`header cell` in
|
|
44
|
+
* TableHeaderCell), the same coverage a word prefix needs. These three
|
|
45
|
+
* are for components and hooks only.
|
|
46
|
+
*
|
|
47
|
+
* A doc's name is a route or key, so docs are left out.
|
|
48
|
+
* @param {string[]} words - The query's words, stopwords included.
|
|
49
|
+
* @param {Candidate} candidate
|
|
50
|
+
* @returns {{score: number, reason: string, covered: Set<string>, alias?: 'partial' | 'keyword', aliasWords?: number} | null}
|
|
51
|
+
* `covered` holds the run's words and every stretch of them joined. `alias`
|
|
52
|
+
* marks a hit on part of a name or on a keyword, not on the whole name.
|
|
53
|
+
*/
|
|
54
|
+
export function compoundHit(words: string[], candidate: Candidate): {
|
|
55
|
+
score: number;
|
|
56
|
+
reason: string;
|
|
57
|
+
covered: Set<string>;
|
|
58
|
+
alias?: "partial" | "keyword";
|
|
59
|
+
aliasWords?: number;
|
|
60
|
+
} | null;
|
|
19
61
|
/**
|
|
20
62
|
* Split a query into meaningful content tokens (lowercased, stopwords + very
|
|
21
63
|
* short words removed). Empty for single-word queries (callers fall back to
|
|
@@ -40,19 +82,20 @@ export function tokenizeQuery(term: string): string[];
|
|
|
40
82
|
* typography/font-setup, `side panel` is "Side panels");
|
|
41
83
|
* - 1: a word of the query is the topic's name (`illustration` in a longer
|
|
42
84
|
* question is the illustrations guide);
|
|
85
|
+
* - 1: a query of two or more words is one of the topic's own declared
|
|
86
|
+
* keywords, whatever the plural (`code review` on a guide that declares it);
|
|
43
87
|
* - 1: the query holds one of the doc's titles whole (`resizable side panels`
|
|
44
88
|
* names "Side panels"; `light dark mode button` names "Light/Dark Mode");
|
|
45
89
|
* - 1: the doc matches every word of the query and one of them is a word of
|
|
46
90
|
* its title (`switch to a dark theme` and "Use a theme").
|
|
47
91
|
* A section answers to its topic's name.
|
|
48
92
|
*
|
|
49
|
-
* A doc that matched only by
|
|
93
|
+
* A doc that matched only by a heading holding the query, by one word, or by
|
|
50
94
|
* words spread through its text has no priority. Docs are split into many
|
|
51
|
-
* small topics,
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* above the component. Broad reference pages match every word of many queries
|
|
95
|
+
* small topics, each with its own headings, so a common phrase such as
|
|
96
|
+
* `font size` hits a heading exactly (170) while the component the reader is
|
|
97
|
+
* after matches one word by keyword (`Text`, 98). Ranked on text alone, every
|
|
98
|
+
* split adds another doc above the component. Broad reference pages match every word of many queries
|
|
56
99
|
* in their text the same way. The score stays the text-match strength the
|
|
57
100
|
* result reports, so callers that gate on it (`build`) see the same numbers.
|
|
58
101
|
*
|
|
@@ -67,7 +110,7 @@ export function domainPriority(term: string, tokens: string[], candidate: Candid
|
|
|
67
110
|
score: number;
|
|
68
111
|
matched: number;
|
|
69
112
|
total: number;
|
|
70
|
-
}): 0 | 1 | 2;
|
|
113
|
+
}, queryWords?: string[]): 0 | 1 | 2;
|
|
71
114
|
/**
|
|
72
115
|
* The first title or heading that holds every word of the query, in order and
|
|
73
116
|
* side by side, or null.
|
|
@@ -89,18 +132,26 @@ export function titleInQuery(term: string, titles: string[] | undefined): string
|
|
|
89
132
|
* @param {string} term - Lowercased full query.
|
|
90
133
|
* @param {string[]} tokens - Content tokens from tokenizeQuery(term).
|
|
91
134
|
* @param {Candidate} candidate
|
|
92
|
-
* @
|
|
135
|
+
* @param {string[]} [words] - The query's words for compound names (see
|
|
136
|
+
* compoundHit); empty when the query names an entry outright.
|
|
137
|
+
* @param {{plain?: boolean}} [opts] - `plain`: score without matches on part
|
|
138
|
+
* of a name or a joined keyword.
|
|
139
|
+
* @returns {{score: number, reason: string, matched: number, total: number, alias?: 'partial' | 'keyword', aliasWords?: number} | null}
|
|
93
140
|
* `matched`/`total` are the query concepts this candidate answered, out of
|
|
94
141
|
* the concepts the query had. Callers that must distinguish "matched one word
|
|
95
142
|
* of three" from "matched all three" — `build`, which gates its pages group
|
|
96
143
|
* on coverage — cannot recover that from the score, because a single strong
|
|
97
144
|
* hit and a broad weak one land on the same number.
|
|
98
145
|
*/
|
|
99
|
-
export function scoreQuery(term: string, tokens: string[], candidate: Candidate
|
|
146
|
+
export function scoreQuery(term: string, tokens: string[], candidate: Candidate, words?: string[], { plain }?: {
|
|
147
|
+
plain?: boolean;
|
|
148
|
+
}): {
|
|
100
149
|
score: number;
|
|
101
150
|
reason: string;
|
|
102
151
|
matched: number;
|
|
103
152
|
total: number;
|
|
153
|
+
alias?: "partial" | "keyword";
|
|
154
|
+
aliasWords?: number;
|
|
104
155
|
} | null;
|
|
105
156
|
/**
|
|
106
157
|
* Score a single candidate against the search term across name, keywords,
|
|
@@ -118,8 +169,9 @@ export function scoreQuery(term: string, tokens: string[], candidate: Candidate)
|
|
|
118
169
|
* @param {string} [candidate.description]
|
|
119
170
|
* @param {string[]} [candidate.prose] - Extra free-text blobs (doc section text, best practices).
|
|
120
171
|
* @param {string[]} [candidate.guidance] - Usage guidance (features, best practices) — scored a tier below description.
|
|
121
|
-
* @param {{fuzzy?: boolean}} [opts] - `fuzzy`: allow edit-distance (typo) matches. Default true; multi-word queries pass false.
|
|
122
|
-
* @returns {{score: number, reason: string} | null}
|
|
172
|
+
* @param {{fuzzy?: boolean, joins?: boolean}} [opts] - `fuzzy`: allow edit-distance (typo) matches. Default true; multi-word queries pass false. `joins`: read a spaced query joined into a name or keyword (default true); off when the query names an entry outright.
|
|
173
|
+
* @returns {{score: number, reason: string, alias?: 'partial' | 'keyword'} | null}
|
|
174
|
+
* `alias` marks a hit that read the query's words joined.
|
|
123
175
|
*/
|
|
124
176
|
export function scoreCandidate(term: string, { name, aliases, domain, keywords, weakKeywords, description, prose, guidance, }: {
|
|
125
177
|
name: string;
|
|
@@ -130,11 +182,13 @@ export function scoreCandidate(term: string, { name, aliases, domain, keywords,
|
|
|
130
182
|
description?: string | undefined;
|
|
131
183
|
prose?: string[] | undefined;
|
|
132
184
|
guidance?: string[] | undefined;
|
|
133
|
-
}, { fuzzy }?: {
|
|
185
|
+
}, { fuzzy, joins }?: {
|
|
134
186
|
fuzzy?: boolean;
|
|
187
|
+
joins?: boolean;
|
|
135
188
|
}): {
|
|
136
189
|
score: number;
|
|
137
190
|
reason: string;
|
|
191
|
+
alias?: "partial" | "keyword";
|
|
138
192
|
} | null;
|
|
139
193
|
/**
|
|
140
194
|
* The components (name and keywords) a search response was scored against, or
|
|
@@ -172,7 +226,7 @@ export function componentKeywords(coreDir: string, cwd: string): Promise<{
|
|
|
172
226
|
*/
|
|
173
227
|
export function search(query: string, options?: {
|
|
174
228
|
cwd?: string | undefined;
|
|
175
|
-
type?: "
|
|
229
|
+
type?: "component" | "hook" | "doc" | "template" | "theme" | undefined;
|
|
176
230
|
limit?: number | undefined;
|
|
177
231
|
}): Promise<import("./search.type.mjs").SearchResponse>;
|
|
178
232
|
export namespace SYNONYMS {
|
|
@@ -213,6 +267,12 @@ export type Candidate = {
|
|
|
213
267
|
*/
|
|
214
268
|
aliases?: string[] | undefined;
|
|
215
269
|
keywords?: string[] | undefined;
|
|
270
|
+
/**
|
|
271
|
+
* - A doc's own declared keywords: what its
|
|
272
|
+
* author lists in `keywords`, without the code terms and table cells its
|
|
273
|
+
* other keywords add.
|
|
274
|
+
*/
|
|
275
|
+
_declared?: string[] | undefined;
|
|
216
276
|
weakKeywords?: string[] | undefined;
|
|
217
277
|
description?: string | undefined;
|
|
218
278
|
prose?: string[] | undefined;
|
|
@@ -21,7 +21,8 @@ export const doc = {
|
|
|
21
21
|
'incidental prose mentions, so an exact match always sorts first. A component\'s ' +
|
|
22
22
|
'usage guidance (its best practices) is indexed one tier below its description, ' +
|
|
23
23
|
'so the words a reader types still find it — but a component that IS the answer ' +
|
|
24
|
-
'always outranks one whose advice merely mentions the term.'
|
|
24
|
+
'always outranks one whose advice merely mentions the term.' +
|
|
25
|
+
" In global mode: with `cwd` outside a project, items from integrations installed next to this CLI package globally are searched too, and theme results name no step that adds a theme to an app; inside a project, only the project's own integrations count. See {@link namespace:global} and {@link generic:computer-integrations}.",
|
|
25
26
|
importPath: '@astryxdesign/cli/api',
|
|
26
27
|
signature:
|
|
27
28
|
'search(query: string, options?: SearchOptions): Promise<SearchResponse>',
|
|
@@ -48,14 +49,14 @@ export const doc = {
|
|
|
48
49
|
name: 'options.cwd',
|
|
49
50
|
type: 'string',
|
|
50
51
|
description:
|
|
51
|
-
"Directory to resolve @astryxdesign/core from. A docs-only or themes-only search (`type: 'doc'` or `type: 'theme'`) does not need it
|
|
52
|
+
"Directory to resolve @astryxdesign/core from: the project's installed Core, else, outside a project or in a project with nothing installed, the Core of the release that answers, installed into the per-user cache first when needed. A docs-only or themes-only search (`type: 'doc'` or `type: 'theme'`) does not need it. A search with no `type` covers the docs and themes alone only when that Core cannot be obtained, and then says so in `meta.partial`.",
|
|
52
53
|
},
|
|
53
54
|
],
|
|
54
55
|
returns: [
|
|
55
56
|
{
|
|
56
57
|
type: 'search',
|
|
57
58
|
description:
|
|
58
|
-
'The query echoed back, `matchCount` (how many candidates matched in total, before `limit`), plus a ranked SearchResultEntry[] bounded by `limit`: each has domain, name, score, reason, description, and follow-up command, plus `import` for components and hooks, `title` for docs, `displayName` and `kind` for templates, and `displayName` for themes. A doc result is the smallest part that answers: one section (with `section`, and a command that reads only it), one docs-tree route, or a topic, whose command lists its sections. `parent` is the command that opens the level above it: the section list of its topic, the namespace a tree node sits in, the Unorganized level for a flat topic, or the topic list for a top-level namespace. Every doc result also carries `package`, the npm package that authored it (for a section, the package its file came from). A theme result is one theme you can import: `name` is its slug, its command is `astryx theme add <slug
|
|
59
|
+
'The query echoed back, `matchCount` (how many candidates matched in total, before `limit`), plus a ranked SearchResultEntry[] bounded by `limit`: each has domain, name, score, reason, description, and follow-up command, plus `import` for components and hooks, `title` for docs, `displayName` and `kind` for templates, and `displayName` for themes. A doc result is the smallest part that answers: one section (with `section`, and a command that reads only it), one docs-tree route, or a topic, whose command lists its sections. `parent` is the command that opens the level above it: the section list of its topic, the namespace a tree node sits in, the Unorganized level for a flat topic, or the topic list for a top-level namespace. Every doc result also carries `package`, the npm package that authored it (for a section, the package its file came from). A theme result is one theme you can import: `name` is its slug, its command is `astryx theme add <slug>` (outside a project, where there is no app to add it to, `astryx theme eject <slug>`), and `package` is the npm package that ships it (`@astryxdesign/cli` for the CLI\'s own themes). When a search with no `type` could not obtain @astryxdesign/core, `meta.partial` is `{skipped, reason}`: the domains it skipped (`component`, `hook`, `template`) and why; the results are the docs and themes, and text mode prints one line on standard error.',
|
|
59
60
|
},
|
|
60
61
|
],
|
|
61
62
|
throws: [
|
|
@@ -67,6 +68,10 @@ export const doc = {
|
|
|
67
68
|
code: 'ERR_CORE_NOT_FOUND',
|
|
68
69
|
when: '@astryxdesign/core cannot be found from the cwd, and `type` names a domain that reads it: `component`, `hook`, or `template`',
|
|
69
70
|
},
|
|
71
|
+
{
|
|
72
|
+
code: 'ERR_VERSIONS_UNAVAILABLE',
|
|
73
|
+
when: "`type` names a domain that reads @astryxdesign/core, and outside a project, or in a project with nothing installed, the Core of the release that answers cannot be installed into the per-user cache; a search with no `type` answers with `meta.partial` instead",
|
|
74
|
+
},
|
|
70
75
|
],
|
|
71
76
|
examples: [
|
|
72
77
|
{label: 'Find a component', code: "const r = await search('button');"},
|
|
@@ -75,14 +75,75 @@ async function placedGuides(route, seen = new Set()) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
describe('search domain priority — the rule', () => {
|
|
78
|
-
it('gives a doc no priority for a
|
|
78
|
+
it('gives a doc no priority for a heading match or a one-word keyword', () => {
|
|
79
79
|
const topic = {
|
|
80
80
|
domain: 'doc',
|
|
81
81
|
name: 'typography/font-setup',
|
|
82
|
-
keywords: ['
|
|
82
|
+
keywords: ['size'],
|
|
83
83
|
titles: ['Font Setup', 'Font Sizes'],
|
|
84
84
|
};
|
|
85
85
|
expect(priority('font size', topic)).toBe(0);
|
|
86
|
+
expect(priority('size', topic)).toBe(0);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('gives a doc priority when the query is one of its declared keywords', () => {
|
|
90
|
+
const guide = {
|
|
91
|
+
domain: 'doc',
|
|
92
|
+
name: 'guides/quality',
|
|
93
|
+
titles: ['Is my code good?'],
|
|
94
|
+
keywords: ['code review', 'review my code'],
|
|
95
|
+
_declared: ['code review', 'review my code'],
|
|
96
|
+
};
|
|
97
|
+
expect(priority('code review', guide)).toBe(1);
|
|
98
|
+
expect(priority('Code Reviews', guide)).toBe(1);
|
|
99
|
+
expect(priority('review my code', guide)).toBe(1);
|
|
100
|
+
// A section's keywords are its headings and code terms.
|
|
101
|
+
const section = {
|
|
102
|
+
...guide,
|
|
103
|
+
name: 'before-you-ship',
|
|
104
|
+
_topic: 'guides/quality',
|
|
105
|
+
_section: 'before-you-ship',
|
|
106
|
+
};
|
|
107
|
+
expect(priority('code review', section)).toBe(0);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("gives a doc no priority for a code term or table cell it didn't declare", () => {
|
|
111
|
+
// A typed doc's keywords hold the first column of its tables and the code
|
|
112
|
+
// terms its text mentions; `missing_field` reads as two words.
|
|
113
|
+
const reference = {
|
|
114
|
+
domain: 'doc',
|
|
115
|
+
name: 'cli/api/functions/validate-integration',
|
|
116
|
+
titles: ['validateIntegration'],
|
|
117
|
+
keywords: ['validate-integration', 'missing_field', 'file required'],
|
|
118
|
+
_declared: [],
|
|
119
|
+
_topic: 'cli/api/functions/validate-integration',
|
|
120
|
+
};
|
|
121
|
+
expect(priority('missing field', reference)).toBe(0);
|
|
122
|
+
expect(priority('file required', reference)).toBe(0);
|
|
123
|
+
expect(
|
|
124
|
+
priority('missing field', {...reference, _declared: ['missing field']}),
|
|
125
|
+
).toBe(1);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('keeps a component the query names exactly above a doc that declares it', async () => {
|
|
129
|
+
const tokens = tokenizeQuery('empty state');
|
|
130
|
+
const component = {domain: 'component', name: 'EmptyState'};
|
|
131
|
+
const doc = {
|
|
132
|
+
domain: 'doc',
|
|
133
|
+
name: 'illustrations',
|
|
134
|
+
keywords: ['empty state'],
|
|
135
|
+
_declared: ['empty state'],
|
|
136
|
+
};
|
|
137
|
+
const c = scoreQuery('empty state', tokens, component);
|
|
138
|
+
const d = scoreQuery('empty state', tokens, doc);
|
|
139
|
+
expect(
|
|
140
|
+
domainPriority('empty state', tokens, /** @type {any} */ (component), c),
|
|
141
|
+
).toBe(1);
|
|
142
|
+
expect(
|
|
143
|
+
domainPriority('empty state', tokens, /** @type {any} */ (doc), d),
|
|
144
|
+
).toBe(1);
|
|
145
|
+
// Both have priority, so the stronger match wins: the exact name.
|
|
146
|
+
expect(c?.score).toBeGreaterThan(d?.score ?? 0);
|
|
86
147
|
});
|
|
87
148
|
|
|
88
149
|
it('gives a doc priority when the query names it', () => {
|
|
@@ -190,32 +251,61 @@ describe('search domain priority — the rule', () => {
|
|
|
190
251
|
|
|
191
252
|
describe('search domain priority — real docs and components', () => {
|
|
192
253
|
it(
|
|
193
|
-
'finds
|
|
254
|
+
'finds a guide that declares the whole phrase above a component that matches one word',
|
|
194
255
|
async () => {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
r => r.domain === '
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
256
|
+
const results = (await search('font size', {cwd})).data.results;
|
|
257
|
+
expect(results[0]).toMatchObject({domain: 'doc'});
|
|
258
|
+
expect(results[0].name).toMatch(/^typography(?:\/|$)/);
|
|
259
|
+
// The component the phrase points to stays near the top.
|
|
260
|
+
expect(
|
|
261
|
+
results
|
|
262
|
+
.slice(0, 3)
|
|
263
|
+
.some(r => r.domain === 'component' && r.name === 'Text'),
|
|
264
|
+
).toBe(true);
|
|
265
|
+
},
|
|
266
|
+
SLOW,
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
it(
|
|
270
|
+
'keeps a component above a reference doc whose table or code terms hold the phrase',
|
|
271
|
+
async () => {
|
|
272
|
+
for (const q of ['missing field', 'file required']) {
|
|
273
|
+
const [top] = (await search(q, {cwd})).data.results;
|
|
274
|
+
expect(top, q).toMatchObject({domain: 'component', name: 'Field'});
|
|
206
275
|
}
|
|
207
276
|
},
|
|
208
277
|
SLOW,
|
|
209
278
|
);
|
|
210
279
|
|
|
211
280
|
it(
|
|
212
|
-
'
|
|
281
|
+
'opens the guide that answers a declared phrase, not one that only mentions it',
|
|
282
|
+
async () => {
|
|
283
|
+
const [layers] = (await search('cascade layers', {cwd})).data.results;
|
|
284
|
+
expect(layers).toMatchObject({
|
|
285
|
+
domain: 'doc',
|
|
286
|
+
name: 'migration/migration-setup',
|
|
287
|
+
});
|
|
288
|
+
const [keyboard] = (await search('keyboard navigation', {cwd})).data
|
|
289
|
+
.results;
|
|
290
|
+
expect(keyboard?.name).not.toBe('migration/migration-verification');
|
|
291
|
+
},
|
|
292
|
+
SLOW,
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
it(
|
|
296
|
+
'keeps a component above docs that match only by a heading, with scores unchanged',
|
|
213
297
|
async () => {
|
|
214
298
|
const results = (await search('font size', {cwd})).data.results;
|
|
215
|
-
const
|
|
216
|
-
r => r.domain === '
|
|
299
|
+
const text = results.findIndex(
|
|
300
|
+
r => r.domain === 'component' && r.name === 'Text',
|
|
217
301
|
);
|
|
218
|
-
expect(
|
|
302
|
+
expect(text).toBeGreaterThanOrEqual(0);
|
|
303
|
+
// A doc below Text outscores it on text alone: priority moved it, not the score.
|
|
304
|
+
expect(
|
|
305
|
+
results
|
|
306
|
+
.slice(text + 1)
|
|
307
|
+
.some(r => r.domain === 'doc' && r.score > results[text].score),
|
|
308
|
+
).toBe(true);
|
|
219
309
|
},
|
|
220
310
|
SLOW,
|
|
221
311
|
);
|