@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
|
@@ -15,8 +15,13 @@ import * as fs from 'node:fs';
|
|
|
15
15
|
import * as os from 'node:os';
|
|
16
16
|
import * as path from 'node:path';
|
|
17
17
|
import {fileURLToPath} from 'node:url';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
search,
|
|
20
|
+
scoreCandidate,
|
|
21
|
+
SEARCH_DOMAINS,
|
|
22
|
+
} from '../../../api/search/search.mjs';
|
|
19
23
|
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
24
|
+
import {linkThisCliAsProjectCli} from '../../../test-utils/release-fixtures.mjs';
|
|
20
25
|
|
|
21
26
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
22
27
|
// Run against the monorepo root so @astryxdesign/core is discoverable.
|
|
@@ -58,123 +63,147 @@ function printsField(lines, key, value) {
|
|
|
58
63
|
// `astryx` bin is installed), so compare the part after `astryx`.
|
|
59
64
|
const text = asText(value).split('\n')[0].trimEnd();
|
|
60
65
|
const shown = text.replace(/^astryx /, '');
|
|
61
|
-
return lines.some(
|
|
66
|
+
return lines.some(
|
|
67
|
+
line => line.startsWith(`${key}:`) && line.trimEnd().endsWith(shown),
|
|
68
|
+
);
|
|
62
69
|
}
|
|
63
70
|
|
|
64
|
-
describe(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
expect(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
expect(data.results.map(r => r.name)).toContain('neutral');
|
|
128
|
-
for (const r of data.results) {
|
|
129
|
-
expect(r.domain).toBe('theme');
|
|
130
|
-
expect(r.command).toBe(`astryx theme add ${r.name}`);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('respects --limit', async () => {
|
|
135
|
-
const {data} = await search('button', {...OPTS, limit: 3});
|
|
136
|
-
expect(data.results.length).toBeLessThanOrEqual(3);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('rejects an unknown --type', async () => {
|
|
140
|
-
await expect(search('x', {...OPTS, type: 'bogus'})).rejects.toThrow(/Unknown --type/);
|
|
141
|
-
});
|
|
142
|
-
}, SCAN_TIMEOUT);
|
|
143
|
-
|
|
144
|
-
describe('search() API — fuzzy / typo tolerance', () => {
|
|
145
|
-
it('finds Button for the typo "buton"', async () => {
|
|
146
|
-
const {data} = await search('buton', OPTS);
|
|
147
|
-
const button = data.results.find(r => r.name === 'Button');
|
|
148
|
-
expect(button).toBeTruthy();
|
|
149
|
-
expect(button.domain).toBe('component');
|
|
150
|
-
});
|
|
151
|
-
}, SCAN_TIMEOUT);
|
|
152
|
-
|
|
153
|
-
describe('search() API — empty + envelope', () => {
|
|
154
|
-
it('returns an empty result set (not an error) for a no-match query', async () => {
|
|
155
|
-
const {type, data} = await search('zzqqxx_definitely_no_match', OPTS);
|
|
156
|
-
expect(type).toBe('search');
|
|
157
|
-
expect(data.results).toEqual([]);
|
|
158
|
-
expect(data.query).toBe('zzqqxx_definitely_no_match');
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it('throws when the query is empty', async () => {
|
|
162
|
-
await expect(search('', OPTS)).rejects.toThrow(/query is required/);
|
|
163
|
-
});
|
|
71
|
+
describe(
|
|
72
|
+
'search() API — ranking',
|
|
73
|
+
() => {
|
|
74
|
+
it('ranks an exact component name match first', async () => {
|
|
75
|
+
const {data} = await search('button', OPTS);
|
|
76
|
+
expect(data.results.length).toBeGreaterThan(0);
|
|
77
|
+
const top = data.results[0];
|
|
78
|
+
expect(top.domain).toBe('component');
|
|
79
|
+
expect(top.name).toBe('Button');
|
|
80
|
+
expect(top.score).toBe(100);
|
|
81
|
+
expect(top.command).toBe('astryx component Button');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('returns components/hooks tagged with a matching keyword', async () => {
|
|
85
|
+
const {data} = await search('button', OPTS);
|
|
86
|
+
// IconButton carries the "button" keyword; should be present and scored
|
|
87
|
+
// on a keyword (not name) signal.
|
|
88
|
+
const iconButton = data.results.find(r => r.name === 'IconButton');
|
|
89
|
+
expect(iconButton).toBeTruthy();
|
|
90
|
+
expect(iconButton.domain).toBe('component');
|
|
91
|
+
expect(iconButton.score).toBeGreaterThanOrEqual(70);
|
|
92
|
+
expect(iconButton.reason.toLowerCase()).toContain('keyword');
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
SCAN_TIMEOUT,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
describe(
|
|
99
|
+
'search() API — cross-domain',
|
|
100
|
+
() => {
|
|
101
|
+
it('returns results from more than one domain for a broad query', async () => {
|
|
102
|
+
const {data} = await search('color', OPTS);
|
|
103
|
+
const domains = new Set(data.results.map(r => r.domain));
|
|
104
|
+
// "color" is a doc topic AND appears across components.
|
|
105
|
+
expect(domains.has('doc')).toBe(true);
|
|
106
|
+
expect(domains.size).toBeGreaterThan(1);
|
|
107
|
+
// The doc topic should carry a follow-up `astryx docs` command.
|
|
108
|
+
const docHit = data.results.find(r => r.domain === 'doc');
|
|
109
|
+
expect(docHit.command.startsWith('astryx docs ')).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('every result is tagged with a known domain and a command', async () => {
|
|
113
|
+
const {data} = await search('button', OPTS);
|
|
114
|
+
for (const r of data.results) {
|
|
115
|
+
expect(SEARCH_DOMAINS).toContain(r.domain);
|
|
116
|
+
expect(typeof r.command).toBe('string');
|
|
117
|
+
expect(r.command.length).toBeGreaterThan(0);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
SCAN_TIMEOUT,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
describe(
|
|
125
|
+
'search() API — filters',
|
|
126
|
+
() => {
|
|
127
|
+
it('--type component returns only components', async () => {
|
|
128
|
+
const {data} = await search('modal', {...OPTS, type: 'component'});
|
|
129
|
+
expect(data.results.length).toBeGreaterThan(0);
|
|
130
|
+
for (const r of data.results) {
|
|
131
|
+
expect(r.domain).toBe('component');
|
|
132
|
+
}
|
|
133
|
+
});
|
|
164
134
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
135
|
+
it('--type doc returns only docs', async () => {
|
|
136
|
+
const {data} = await search('color', {...OPTS, type: 'doc'});
|
|
137
|
+
for (const r of data.results) {
|
|
138
|
+
expect(r.domain).toBe('doc');
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('--type theme returns only themes, each with the command that adds it', async () => {
|
|
143
|
+
const {data} = await search('warm', {...OPTS, type: 'theme'});
|
|
144
|
+
expect(data.results.map(r => r.name)).toContain('neutral');
|
|
145
|
+
for (const r of data.results) {
|
|
146
|
+
expect(r.domain).toBe('theme');
|
|
147
|
+
expect(r.command).toBe(`astryx theme add ${r.name}`);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('respects --limit', async () => {
|
|
152
|
+
const {data} = await search('button', {...OPTS, limit: 3});
|
|
153
|
+
expect(data.results.length).toBeLessThanOrEqual(3);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('rejects an unknown --type', async () => {
|
|
157
|
+
await expect(search('x', {...OPTS, type: 'bogus'})).rejects.toThrow(
|
|
158
|
+
/Unknown --type/,
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
SCAN_TIMEOUT,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
describe(
|
|
166
|
+
'search() API — fuzzy / typo tolerance',
|
|
167
|
+
() => {
|
|
168
|
+
it('finds Button for the typo "buton"', async () => {
|
|
169
|
+
const {data} = await search('buton', OPTS);
|
|
170
|
+
const button = data.results.find(r => r.name === 'Button');
|
|
171
|
+
expect(button).toBeTruthy();
|
|
172
|
+
expect(button.domain).toBe('component');
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
SCAN_TIMEOUT,
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
describe(
|
|
179
|
+
'search() API — empty + envelope',
|
|
180
|
+
() => {
|
|
181
|
+
it('returns an empty result set (not an error) for a no-match query', async () => {
|
|
182
|
+
const {type, data} = await search('zzqqxx_definitely_no_match', OPTS);
|
|
183
|
+
expect(type).toBe('search');
|
|
184
|
+
expect(data.results).toEqual([]);
|
|
185
|
+
expect(data.query).toBe('zzqqxx_definitely_no_match');
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('throws when the query is empty', async () => {
|
|
189
|
+
await expect(search('', OPTS)).rejects.toThrow(/query is required/);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('returns the correct envelope shape', async () => {
|
|
193
|
+
const result = await search('button', OPTS);
|
|
194
|
+
expect(result.type).toBe('search');
|
|
195
|
+
expect(result.data).toHaveProperty('query');
|
|
196
|
+
expect(Array.isArray(result.data.results)).toBe(true);
|
|
197
|
+
const top = result.data.results[0];
|
|
198
|
+
expect(top).toHaveProperty('domain');
|
|
199
|
+
expect(top).toHaveProperty('name');
|
|
200
|
+
expect(top).toHaveProperty('score');
|
|
201
|
+
expect(top).toHaveProperty('description');
|
|
202
|
+
expect(top).toHaveProperty('command');
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
SCAN_TIMEOUT,
|
|
206
|
+
);
|
|
178
207
|
|
|
179
208
|
describe('scoreCandidate()', () => {
|
|
180
209
|
it('scores an exact name match at 100', () => {
|
|
@@ -183,199 +212,303 @@ describe('scoreCandidate()', () => {
|
|
|
183
212
|
|
|
184
213
|
it('scores an exact keyword above a description mention', () => {
|
|
185
214
|
const kw = scoreCandidate('toggle', {name: 'Switch', keywords: ['toggle']});
|
|
186
|
-
const desc = scoreCandidate('toggle', {
|
|
215
|
+
const desc = scoreCandidate('toggle', {
|
|
216
|
+
name: 'Switch',
|
|
217
|
+
description: 'A toggle control',
|
|
218
|
+
});
|
|
187
219
|
expect(kw.score).toBeGreaterThan(desc.score);
|
|
188
220
|
});
|
|
189
221
|
|
|
190
222
|
it('returns null when nothing matches', () => {
|
|
191
|
-
expect(
|
|
223
|
+
expect(
|
|
224
|
+
scoreCandidate('zzzz', {name: 'Button', keywords: ['cta']}),
|
|
225
|
+
).toBeNull();
|
|
192
226
|
});
|
|
193
227
|
});
|
|
194
228
|
|
|
195
|
-
describe(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
search('x', {...OPTS, limit: Number(value)}),
|
|
236
|
-
).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
|
|
237
|
-
const json = await runCli(['--json', 'search', 'x', '--limit', value], REPO_ROOT);
|
|
238
|
-
expect(json.status).toBe(1);
|
|
239
|
-
expect(JSON.parse(json.stdout)).toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
|
|
240
|
-
const text = await runCli(['search', 'x', '--limit', value], REPO_ROOT);
|
|
241
|
-
expect(text.status).toBe(1);
|
|
242
|
-
},
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
it('emits a valid --json envelope', async () => {
|
|
246
|
-
const r = await runCli(['--json', 'search', 'button'], REPO_ROOT);
|
|
247
|
-
expect(r.status).toBe(0);
|
|
248
|
-
const parsed = JSON.parse(r.stdout);
|
|
249
|
-
expect(parsed.apiVersion).toBe(1);
|
|
250
|
-
expect(parsed.type).toBe('search');
|
|
251
|
-
expect(parsed.data.query).toBe('button');
|
|
252
|
-
expect(Array.isArray(parsed.data.results)).toBe(true);
|
|
253
|
-
expect(parsed.data.matchCount).toBeGreaterThanOrEqual(
|
|
254
|
-
parsed.data.results.length,
|
|
255
|
-
);
|
|
256
|
-
expect(parsed.data.results[0].name).toBe('Button');
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
it('says how many matched when --limit cut the list short', async () => {
|
|
260
|
-
// The text view is a projection of the JSON, and the JSON now carries the
|
|
261
|
-
// match total. A bare "(2)" heading over a capped list reads as "that is
|
|
262
|
-
// all Astryx has", which is the conclusion `search` exists to prevent.
|
|
263
|
-
const capped = await runCli(
|
|
264
|
-
['search', 'button', '--type', 'component', '--limit', '2'],
|
|
265
|
-
REPO_ROOT,
|
|
229
|
+
describe(
|
|
230
|
+
'search CLI — exit codes + JSON contract',
|
|
231
|
+
() => {
|
|
232
|
+
it('exits 0 for a successful search', async () => {
|
|
233
|
+
const r = await runCli(['search', 'button'], REPO_ROOT);
|
|
234
|
+
expect(r.status).toBe(0);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('exits 0 for a no-match query (valid empty result, not failure)', async () => {
|
|
238
|
+
const r = await runCli(['search', 'zzqqxx_no_match'], REPO_ROOT);
|
|
239
|
+
expect(r.status).toBe(0);
|
|
240
|
+
expect(r.stdout).toContain('No results');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it(
|
|
244
|
+
'takes every word after `search` as one query',
|
|
245
|
+
async () => {
|
|
246
|
+
// Commander took only the first word, so `search dark mode` searched for
|
|
247
|
+
// "dark" and dropped "mode" without a word.
|
|
248
|
+
const json = await runCli(
|
|
249
|
+
['--json', 'search', 'dark', 'mode', '--type', 'doc'],
|
|
250
|
+
REPO_ROOT,
|
|
251
|
+
);
|
|
252
|
+
expect(json.status).toBe(0);
|
|
253
|
+
const env = JSON.parse(json.stdout);
|
|
254
|
+
expect(env.data.query).toBe('dark mode');
|
|
255
|
+
// theme topic-level and section tie; either is correct
|
|
256
|
+
const top = env.data.results[0];
|
|
257
|
+
expect(
|
|
258
|
+
top.name === 'theme' ||
|
|
259
|
+
top.name === 'use-a-theme' ||
|
|
260
|
+
top.section === 'light-dark-mode',
|
|
261
|
+
).toBe(true);
|
|
262
|
+
const text = await runCli(
|
|
263
|
+
['search', 'dark', 'mode', '--type', 'doc'],
|
|
264
|
+
REPO_ROOT,
|
|
265
|
+
);
|
|
266
|
+
expect(text.stdout).toContain('Results for "dark mode"');
|
|
267
|
+
},
|
|
268
|
+
SCAN_TIMEOUT,
|
|
266
269
|
);
|
|
267
|
-
expect(capped.status).toBe(0);
|
|
268
|
-
expect(capped.stdout).toMatch(/^Results for "button" \(2 of \d+\)$/m);
|
|
269
270
|
|
|
270
|
-
|
|
271
|
-
['search', '
|
|
272
|
-
|
|
271
|
+
it('exits 1 for an invalid --type', async () => {
|
|
272
|
+
const r = await runCli(['search', 'x', '--type', 'bogus'], REPO_ROOT);
|
|
273
|
+
expect(r.status).toBe(1);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('exits 1 for an invalid --limit', async () => {
|
|
277
|
+
const r = await runCli(['search', 'x', '--limit', '0'], REPO_ROOT);
|
|
278
|
+
expect(r.status).toBe(1);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it.each(['1.5', '5abc'])(
|
|
282
|
+
'refuses --limit %s like search({limit}) does, in both modes',
|
|
283
|
+
async value => {
|
|
284
|
+
await expect(
|
|
285
|
+
search('x', {...OPTS, limit: Number(value)}),
|
|
286
|
+
).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
|
|
287
|
+
const json = await runCli(
|
|
288
|
+
['--json', 'search', 'x', '--limit', value],
|
|
289
|
+
REPO_ROOT,
|
|
290
|
+
);
|
|
291
|
+
expect(json.status).toBe(1);
|
|
292
|
+
expect(JSON.parse(json.stdout)).toMatchObject({
|
|
293
|
+
code: 'ERR_INVALID_ARGUMENT',
|
|
294
|
+
});
|
|
295
|
+
const text = await runCli(['search', 'x', '--limit', value], REPO_ROOT);
|
|
296
|
+
expect(text.status).toBe(1);
|
|
297
|
+
},
|
|
273
298
|
);
|
|
274
|
-
expect(uncapped.stdout).toMatch(/^Results for "button" \(\d+\)$/m);
|
|
275
|
-
expect(uncapped.stdout).not.toMatch(/Results for "button" \(\d+ of/);
|
|
276
|
-
});
|
|
277
299
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
300
|
+
it('emits a valid --json envelope', async () => {
|
|
301
|
+
const r = await runCli(['--json', 'search', 'button'], REPO_ROOT);
|
|
302
|
+
expect(r.status).toBe(0);
|
|
303
|
+
const parsed = JSON.parse(r.stdout);
|
|
304
|
+
expect(parsed.apiVersion).toBe(1);
|
|
305
|
+
expect(parsed.type).toBe('search');
|
|
306
|
+
expect(parsed.data.query).toBe('button');
|
|
307
|
+
expect(Array.isArray(parsed.data.results)).toBe(true);
|
|
308
|
+
expect(parsed.data.matchCount).toBeGreaterThanOrEqual(
|
|
309
|
+
parsed.data.results.length,
|
|
310
|
+
);
|
|
311
|
+
expect(parsed.data.results[0].name).toBe('Button');
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('says how many matched when --limit cut the list short', async () => {
|
|
315
|
+
// The text view is a projection of the JSON, and the JSON now carries the
|
|
316
|
+
// match total. A bare "(2)" heading over a capped list reads as "that is
|
|
317
|
+
// all Astryx has", which is the conclusion `search` exists to prevent.
|
|
318
|
+
const capped = await runCli(
|
|
319
|
+
['search', 'button', '--type', 'component', '--limit', '2'],
|
|
320
|
+
REPO_ROOT,
|
|
321
|
+
);
|
|
322
|
+
expect(capped.status).toBe(0);
|
|
323
|
+
expect(capped.stdout).toMatch(/^Results for "button" \(2 of \d+\)$/m);
|
|
324
|
+
|
|
325
|
+
const uncapped = await runCli(
|
|
326
|
+
['search', 'button', '--type', 'component', '--limit', '500'],
|
|
327
|
+
REPO_ROOT,
|
|
328
|
+
);
|
|
329
|
+
expect(uncapped.stdout).toMatch(/^Results for "button" \(\d+\)$/m);
|
|
330
|
+
expect(uncapped.stdout).not.toMatch(/Results for "button" \(\d+ of/);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('emits a valid --json envelope with empty results for no match', async () => {
|
|
334
|
+
const r = await runCli(
|
|
335
|
+
['--json', 'search', 'zzqqxx_no_match'],
|
|
336
|
+
REPO_ROOT,
|
|
337
|
+
);
|
|
338
|
+
expect(r.status).toBe(0);
|
|
339
|
+
const parsed = JSON.parse(r.stdout);
|
|
340
|
+
expect(parsed.type).toBe('search');
|
|
341
|
+
expect(parsed.data.results).toEqual([]);
|
|
342
|
+
expect(parsed.data.matchCount).toBe(0);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('renders each result as a greppable key: value record', async () => {
|
|
346
|
+
const r = await runCli(['search', 'button'], REPO_ROOT);
|
|
347
|
+
expect(r.stdout).toMatch(
|
|
348
|
+
/^command:\s+\S.*(?:astryx|@astryxdesign\/cli(?:@\S+)?) component Button$/m,
|
|
349
|
+
);
|
|
350
|
+
// Fields mirror the JSON object and are line-greppable.
|
|
351
|
+
expect(r.stdout).toMatch(/^name:\s+Button$/m);
|
|
352
|
+
expect(r.stdout).toMatch(/^domain:\s+component$/m);
|
|
353
|
+
expect(r.stdout).toContain('description:');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('prints every result field under its JSON key (score and reason with --verbose)', async () => {
|
|
357
|
+
// Between them these reach every domain, so every per-domain field shows.
|
|
358
|
+
// A theme matches `theme` only through its description, a prose mention
|
|
359
|
+
// ranked below every name and keyword hit, so the theme domain comes from
|
|
360
|
+
// a theme's own name.
|
|
361
|
+
const domains = new Set();
|
|
362
|
+
for (const args of [
|
|
363
|
+
['search', 'theme', '--limit', '60'],
|
|
364
|
+
['search', 'neutral', '--type', 'theme'],
|
|
365
|
+
]) {
|
|
366
|
+
const env = JSON.parse(
|
|
367
|
+
(await runCli(['--json', ...args], REPO_ROOT)).stdout,
|
|
368
|
+
);
|
|
369
|
+
const plain = (await runCli(args, REPO_ROOT)).stdout.split('\n');
|
|
370
|
+
const verbose = (
|
|
371
|
+
await runCli([...args, '--verbose'], REPO_ROOT)
|
|
372
|
+
).stdout.split('\n');
|
|
373
|
+
for (const result of env.data.results) {
|
|
374
|
+
domains.add(result.domain);
|
|
375
|
+
for (const [key, value] of Object.entries(result)) {
|
|
376
|
+
if (value == null || value === '') continue;
|
|
377
|
+
const label = `${result.domain} ${result.name}: ${key}`;
|
|
378
|
+
expect(printsField(verbose, key, value), label).toBe(true);
|
|
379
|
+
if (key !== 'score' && key !== 'reason') {
|
|
380
|
+
expect(printsField(plain, key, value), label).toBe(true);
|
|
381
|
+
}
|
|
317
382
|
}
|
|
318
383
|
}
|
|
319
384
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const open = await runCli(['search', 'data', 'table'], REPO_ROOT);
|
|
340
|
-
expect(open.status).toBe(0);
|
|
341
|
-
expect(open.stdout).toMatch(/^More in packages you could add: .*discover 'data table'$/m);
|
|
342
|
-
const none = await runCli(['search', 'zzqqxxnomatch'], REPO_ROOT);
|
|
343
|
-
expect(none.stdout).toMatch(/^More in packages you could add: .*discover zzqqxxnomatch$/m);
|
|
344
|
-
const hooks = await runCli(['search', 'click', '--type', 'hook'], REPO_ROOT);
|
|
345
|
-
expect(hooks.status).toBe(0);
|
|
346
|
-
expect(hooks.stdout).not.toContain('More in packages you could add');
|
|
347
|
-
const json = await runCli(['--json', 'search', 'button'], REPO_ROOT);
|
|
348
|
-
expect(json.stdout).not.toContain('More in packages you could add');
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
it('searches the docs and themes when no @astryxdesign/core is reachable, and exits 1 for --type component', async () => {
|
|
352
|
-
const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-search-cli-no-core-'));
|
|
353
|
-
try {
|
|
354
|
-
const open = await runCli(['--json', 'search', 'make', 'an', 'integration'], empty);
|
|
385
|
+
expect(domains).toEqual(new Set(SEARCH_DOMAINS));
|
|
386
|
+
}, 90_000);
|
|
387
|
+
|
|
388
|
+
it('--verbose exits 0 and prints import/match detail', async () => {
|
|
389
|
+
// Regression: the boolean verbose flag was named --detail, which collided
|
|
390
|
+
// with the value-taking global `--detail <level>` — a bare `search
|
|
391
|
+
// --detail` errored "argument missing" and the verbose output was
|
|
392
|
+
// unreachable. It is now `--verbose`.
|
|
393
|
+
const r = await runCli(['search', 'button', '--verbose'], REPO_ROOT);
|
|
394
|
+
expect(r.status).toBe(0);
|
|
395
|
+
expect(r.stdout).toContain('import:');
|
|
396
|
+
// Ranking detail: pre-formatter this was a single `match: <reason> (score N)`
|
|
397
|
+
// line; it's now separate `score:` / `reason:` record fields mirroring --json.
|
|
398
|
+
expect(r.stdout).toContain('score:');
|
|
399
|
+
expect(r.stdout).toContain('reason:');
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('points at discover for packages that could add more, except for hooks', async () => {
|
|
403
|
+
const open = await runCli(['search', 'data', 'table'], REPO_ROOT);
|
|
355
404
|
expect(open.status).toBe(0);
|
|
356
|
-
expect(
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
expect(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
expect(
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
expect(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
405
|
+
expect(open.stdout).toMatch(
|
|
406
|
+
/^More in packages you could add: .*discover 'data table'$/m,
|
|
407
|
+
);
|
|
408
|
+
const none = await runCli(['search', 'zzqqxxnomatch'], REPO_ROOT);
|
|
409
|
+
expect(none.stdout).toMatch(
|
|
410
|
+
/^More in packages you could add: .*discover zzqqxxnomatch$/m,
|
|
411
|
+
);
|
|
412
|
+
const hooks = await runCli(
|
|
413
|
+
['search', 'click', '--type', 'hook'],
|
|
414
|
+
REPO_ROOT,
|
|
415
|
+
);
|
|
416
|
+
expect(hooks.status).toBe(0);
|
|
417
|
+
expect(hooks.stdout).not.toContain('More in packages you could add');
|
|
418
|
+
const json = await runCli(['--json', 'search', 'button'], REPO_ROOT);
|
|
419
|
+
expect(json.stdout).not.toContain('More in packages you could add');
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it("finds components in an open search outside a project and in a fresh clone, reading the release's own Core", async () => {
|
|
423
|
+
const empty = fs.mkdtempSync(
|
|
424
|
+
path.join(os.tmpdir(), 'astryx-search-cli-carried-'),
|
|
425
|
+
);
|
|
426
|
+
const clone = fs.mkdtempSync(
|
|
427
|
+
path.join(os.tmpdir(), 'astryx-search-cli-clone-'),
|
|
428
|
+
);
|
|
429
|
+
// A fresh clone: it declares Core, with nothing installed.
|
|
430
|
+
fs.writeFileSync(
|
|
431
|
+
path.join(clone, 'package.json'),
|
|
432
|
+
JSON.stringify({
|
|
433
|
+
name: 'clone',
|
|
434
|
+
dependencies: {'@astryxdesign/core': '*'},
|
|
435
|
+
}),
|
|
436
|
+
);
|
|
437
|
+
try {
|
|
438
|
+
for (const dir of [empty, clone]) {
|
|
439
|
+
const run = await runCli(['--json', 'search', 'button'], dir);
|
|
440
|
+
expect(run.status).toBe(0);
|
|
441
|
+
const envelope = JSON.parse(run.stdout);
|
|
442
|
+
expect(envelope.meta?.partial).toBeUndefined();
|
|
443
|
+
expect(
|
|
444
|
+
envelope.data.results.some(
|
|
445
|
+
(/** @type {any} */ r) =>
|
|
446
|
+
r.domain === 'component' && r.name === 'Button',
|
|
447
|
+
),
|
|
448
|
+
).toBe(true);
|
|
449
|
+
}
|
|
450
|
+
} finally {
|
|
451
|
+
fs.rmSync(empty, {recursive: true, force: true});
|
|
452
|
+
fs.rmSync(clone, {recursive: true, force: true});
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('searches the docs and themes when no @astryxdesign/core is reachable, and exits 1 for --type component', async () => {
|
|
457
|
+
const empty = fs.mkdtempSync(
|
|
458
|
+
path.join(os.tmpdir(), 'astryx-search-cli-no-core-'),
|
|
459
|
+
);
|
|
460
|
+
// The project's own CLI answers here and no Core is installed; outside a
|
|
461
|
+
// project the carried Core would answer instead (AST-081 FR3).
|
|
462
|
+
linkThisCliAsProjectCli(empty);
|
|
463
|
+
try {
|
|
464
|
+
const open = await runCli(
|
|
465
|
+
['--json', 'search', 'make', 'an', 'integration'],
|
|
466
|
+
empty,
|
|
467
|
+
);
|
|
468
|
+
expect(open.status).toBe(0);
|
|
469
|
+
expect(JSON.parse(open.stdout).data.results[0]).toMatchObject({
|
|
470
|
+
domain: 'doc',
|
|
471
|
+
});
|
|
472
|
+
// Never silently: JSON names what it skipped and why.
|
|
473
|
+
expect(JSON.parse(open.stdout).meta.partial).toMatchObject({
|
|
474
|
+
skipped: ['component', 'hook', 'template'],
|
|
475
|
+
reason: expect.stringContaining('@astryxdesign/core'),
|
|
476
|
+
});
|
|
477
|
+
// Bundled themes need no project, so an open search finds them too.
|
|
478
|
+
const theme = await runCli(['--json', 'search', 'neutral'], empty);
|
|
479
|
+
expect(theme.status).toBe(0);
|
|
480
|
+
expect(JSON.parse(theme.stdout).data.results[0]).toMatchObject({
|
|
481
|
+
domain: 'theme',
|
|
482
|
+
name: 'neutral',
|
|
483
|
+
});
|
|
484
|
+
// The text says the search covered the docs and themes alone.
|
|
485
|
+
const text = await runCli(['search', 'button'], empty);
|
|
486
|
+
expect(text.status).toBe(0);
|
|
487
|
+
expect(text.stdout).toContain('only the docs and themes were searched');
|
|
488
|
+
expect(text.stderr).toMatch(
|
|
489
|
+
/^astryx: components, hooks, and templates were not searched: /mu,
|
|
490
|
+
);
|
|
491
|
+
// A themes-only search needs no core, like a docs-only one.
|
|
492
|
+
const themes = await runCli(
|
|
493
|
+
['--json', 'search', 'warm', '--type', 'theme'],
|
|
494
|
+
empty,
|
|
495
|
+
);
|
|
496
|
+
expect(themes.status).toBe(0);
|
|
497
|
+
const found = JSON.parse(themes.stdout).data.results;
|
|
498
|
+
expect(found.map(r => r.name)).toContain('neutral');
|
|
499
|
+
expect(found.every(r => r.domain === 'theme')).toBe(true);
|
|
500
|
+
const json = await runCli(
|
|
501
|
+
['--json', 'search', 'button', '--type', 'component'],
|
|
502
|
+
empty,
|
|
503
|
+
);
|
|
504
|
+
expect(json.status).toBe(1);
|
|
505
|
+
expect(JSON.parse(json.stdout)).toMatchObject({
|
|
506
|
+
code: 'ERR_CORE_NOT_FOUND',
|
|
507
|
+
});
|
|
508
|
+
} finally {
|
|
509
|
+
fs.rmSync(empty, {recursive: true, force: true});
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
},
|
|
513
|
+
SCAN_TIMEOUT,
|
|
514
|
+
);
|