@astryxdesign/cli 0.7.2 → 0.7.3-canary.02f5fe4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -71
- package/api/build/_adapter.d.mts +58 -0
- package/api/build/_adapter.mjs +127 -3
- package/api/build/blocks/blocks.d.mts +92 -0
- package/api/build/blocks/blocks.mjs +528 -0
- package/api/build/blocks/blocks.test.mjs +238 -0
- package/api/build/blocks/blocks.weights.json +1 -0
- package/api/build/build.mjs +25 -6
- package/api/build/build.type.mjs +1 -1
- package/api/build/kit/answer.d.mts +18 -0
- package/api/build/kit/answer.mjs +195 -0
- package/api/build/kit/answer.test.mjs +108 -0
- package/api/build/kit/kind.d.mts +25 -0
- package/api/build/kit/kind.mjs +170 -0
- package/api/build/kit/kit.d.mts +2 -4
- package/api/build/kit/kit.mjs +8 -398
- package/api/build/kit/rank.d.mts +3 -32
- package/api/build/kit/rank.mjs +25 -342
- package/api/build/kit/rank.test.mjs +2 -1
- package/api/build/kit/signals.d.mts +79 -0
- package/api/build/kit/signals.mjs +295 -0
- package/api/build/kit/start.d.mts +32 -0
- package/api/build/kit/start.mjs +163 -0
- package/api/build/kit/words.d.mts +72 -0
- package/api/build/kit/words.mjs +202 -0
- package/api/build/tree.d.mts +20 -0
- package/api/build/tree.mjs +53 -0
- package/api/build/tree.test.mjs +185 -0
- package/api/build/tree.weights.json +1 -0
- package/api/component/_adapter.mjs +39 -5
- package/api/component/component-replacement.test.mjs +1 -0
- package/api/component/component.mjs +17 -3
- package/api/component/component.test.mjs +15 -0
- package/api/component/doc-links.test.mjs +2 -2
- package/api/discover/_adapter.d.mts +1 -2
- package/api/discover/_adapter.mjs +42 -17
- package/api/discover/_adapter.test.mjs +42 -0
- package/api/discover/discover.mjs +0 -1
- package/api/docs/_adapter.d.mts +2 -2
- package/api/docs/_adapter.mjs +82 -23
- package/api/docs/docs-homes.test.mjs +127 -0
- package/api/docs/docs.doc.mjs +3 -3
- package/api/docs/docs.test.mjs +35 -19
- package/api/docs/integration-tree.test.mjs +20 -20
- package/api/docs/integrationDocs.test.mjs +1 -1
- package/api/docs/namespace-section.test.mjs +6 -6
- package/api/docs/reference-blocks.test.mjs +2 -2
- package/api/doctor/_adapter.d.mts +33 -13
- package/api/doctor/_adapter.mjs +55 -25
- package/api/doctor/doctor.d.mts +23 -5
- package/api/doctor/doctor.mjs +183 -40
- package/api/doctor/doctor.test.mjs +95 -12
- package/api/hook/hook.mjs +1 -1
- package/api/init/init.doc.mjs +20 -6
- package/api/init/init.test.mjs +18 -2
- package/api/init/init.type.d.mts +3 -3
- package/api/init/init.type.mjs +3 -3
- package/api/init/remove/remove.mjs +17 -4
- package/api/init/remove/remove.test.mjs +114 -2
- package/api/init/run/run.mjs +69 -6
- package/api/integration/_adapter.d.mts +8 -0
- package/api/integration/_adapter.mjs +21 -1
- package/api/integration/authoring-checks.mjs +83 -9
- package/api/integration/authoring-checks.test.mjs +220 -0
- package/api/integration/pack-check.mjs +123 -4
- package/api/integration/pack-check.test.mjs +87 -0
- package/api/integration/validate-integration-case-disk.test.mjs +111 -0
- package/api/integration/validate-integration-fixes.test.mjs +6 -5
- package/api/integration/validate-integration-gaps.test.mjs +1975 -0
- package/api/integration/validate-integration.d.mts +15 -2
- package/api/integration/validate-integration.mjs +298 -39
- package/api/integration/validate-integration.type.d.mts +90 -1
- package/api/integration/validate-integration.type.mjs +67 -2
- package/api/integration/validateIntegration.doc.mjs +1 -1
- package/api/search/ORDERING.md +28 -0
- package/api/search/_adapter.d.mts +82 -2
- package/api/search/_adapter.mjs +157 -10
- package/api/search/_adapter.test.mjs +173 -0
- package/api/search/_candidate-score.d.mts +40 -0
- package/api/search/_candidate-score.mjs +238 -0
- package/api/search/_cards.json +6098 -0
- package/api/search/_compound.d.mts +50 -0
- package/api/search/_compound.mjs +170 -0
- package/api/search/_doc-searcher.d.mts +4 -0
- package/api/search/_doc-searcher.mjs +23 -0
- package/api/search/_doc-searcher.test.mjs +36 -0
- package/api/search/_doc-searcher.weights.json +1 -0
- package/api/search/_doc-text.d.mts +30 -0
- package/api/search/_doc-text.mjs +87 -0
- package/api/search/_entries.d.mts +63 -0
- package/api/search/_entries.mjs +232 -0
- package/api/search/_entries.test.mjs +48 -0
- package/api/search/_features.d.mts +35 -0
- package/api/search/_features.mjs +155 -0
- package/api/search/_gather-components.d.mts +26 -0
- package/api/search/_gather-components.mjs +284 -0
- package/api/search/_gather-docs.d.mts +20 -0
- package/api/search/_gather-docs.mjs +254 -0
- package/api/search/_gather-hooks.d.mts +12 -0
- package/api/search/_gather-hooks.mjs +52 -0
- package/api/search/_gather-templates.d.mts +25 -0
- package/api/search/_gather-templates.mjs +107 -0
- package/api/search/_lexical.d.mts +135 -0
- package/api/search/_lexical.mjs +351 -0
- package/api/search/_main-searcher.d.mts +19 -0
- package/api/search/_main-searcher.mjs +115 -0
- package/api/search/_main-searcher.test.mjs +106 -0
- package/api/search/_main-searcher.weights.json +1 -0
- package/api/search/_module-doc.d.mts +32 -0
- package/api/search/_module-doc.mjs +78 -0
- package/api/search/_order.d.mts +32 -0
- package/api/search/_order.mjs +162 -0
- package/api/search/_order.test.mjs +72 -0
- package/api/search/_priority.d.mts +50 -0
- package/api/search/_priority.mjs +139 -0
- package/api/search/_query-words.d.mts +25 -0
- package/api/search/_query-words.mjs +92 -0
- package/api/search/_query.d.mts +65 -0
- package/api/search/_query.mjs +176 -0
- package/api/search/_result.d.mts +97 -0
- package/api/search/_result.mjs +150 -0
- package/api/search/_score.d.mts +60 -0
- package/api/search/_score.mjs +283 -0
- package/api/search/_synonyms.d.mts +21 -0
- package/api/search/_synonyms.mjs +67 -0
- package/api/search/_template-searcher.d.mts +4 -0
- package/api/search/_template-searcher.mjs +23 -0
- package/api/search/_template-searcher.test.mjs +40 -0
- package/api/search/_template-searcher.weights.json +1 -0
- package/api/search/_titles.d.mts +33 -0
- package/api/search/_titles.mjs +65 -0
- package/api/search/_words.d.mts +64 -0
- package/api/search/_words.mjs +157 -0
- package/api/search/search.d.mts +22 -305
- package/api/search/search.doc.mjs +8 -6
- package/api/search/search.mjs +56 -2482
- package/api/search/search.test.mjs +14 -14
- package/api/search/search.type.d.mts +6 -1
- package/api/search/search.type.mjs +6 -1
- package/api/search/tree.d.mts +15 -0
- package/api/search/tree.mjs +40 -0
- package/api/search/tree.test.mjs +66 -0
- package/api/search/tree.weights.json +1 -0
- package/api/template/template.mjs +5 -1
- package/api/theme/build/build.packed-old-core.test.mjs +1 -0
- package/api/upgrade/_adapter.d.mts +57 -9
- package/api/upgrade/_adapter.mjs +198 -28
- package/api/upgrade/registry/registry.d.mts +10 -4
- package/api/upgrade/registry/registry.mjs +33 -16
- package/api/upgrade/registry/registry.test.mjs +85 -0
- package/api/upgrade/run/run.d.mts +4 -2
- package/api/upgrade/run/run.mjs +13 -2
- package/api/upgrade/run/run.test.mjs +417 -3
- package/api/upgrade/upgrade.doc.mjs +10 -5
- package/api/upgrade/upgrade.mjs +13 -2
- package/api/upgrade/upgrade.test.mjs +194 -0
- package/api/upgrade/upgrade.type.d.mts +5 -3
- package/api/upgrade/upgrade.type.mjs +8 -6
- package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
- package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
- package/assets/docs/author-a-theme.doc.mjs +2 -2
- package/assets/docs/is-my-code-good.doc.mjs +287 -0
- package/assets/docs/tree/add-a-component.doc.mjs +1 -1
- package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
- package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +6 -0
- package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
- package/assets/docs/tree/block-template.doc.mjs +1 -1
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +2 -2
- package/assets/docs/tree/check-the-props.doc.mjs +1 -1
- package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
- package/assets/docs/tree/checks.doc.mjs +3 -3
- package/assets/docs/tree/ci-and-containers.doc.mjs +13 -0
- package/assets/docs/tree/cli-command.doc.mjs +1 -1
- package/assets/docs/tree/cli.doc.mjs +1 -1
- package/assets/docs/tree/codemods.doc.mjs +1 -1
- package/assets/docs/tree/component-family.doc.mjs +1 -1
- package/assets/docs/tree/component-imports.doc.mjs +1 -1
- package/assets/docs/tree/components.doc.mjs +1 -1
- package/assets/docs/tree/configuration.doc.mjs +1 -1
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
- package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
- package/assets/docs/tree/docs.doc.mjs +1 -1
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
- package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
- package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
- package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
- package/assets/docs/tree/global-integrations.doc.mjs +2 -2
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
- package/assets/docs/tree/help.doc.mjs +2 -2
- package/assets/docs/tree/host-entry.doc.mjs +128 -0
- package/assets/docs/tree/links.doc.mjs +1 -1
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +1 -1
- package/assets/docs/tree/publishing.doc.mjs +1 -1
- package/assets/docs/tree/quick-start.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/ship.doc.mjs +2 -2
- package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
- package/assets/docs/tree/single-component.doc.mjs +1 -1
- package/assets/docs/tree/start-a-template.doc.mjs +1 -1
- package/assets/docs/tree/subcomponent.doc.mjs +1 -1
- package/assets/docs/tree/template-assets.doc.mjs +1 -1
- package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
- package/assets/docs/tree/template-icons.doc.mjs +1 -1
- package/assets/docs/tree/template-images-media.doc.mjs +1 -1
- package/assets/docs/tree/template-styles.doc.mjs +1 -1
- package/assets/docs/tree/templates.doc.mjs +1 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
- package/assets/docs/tree/themes.doc.mjs +1 -1
- package/assets/docs/tree/tokens-data.doc.mjs +2 -2
- package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
- package/assets/docs/tree/upgrading.doc.mjs +1 -1
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
- package/assets/docs/tree/versioning.doc.mjs +5 -1
- package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
- package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
- package/assets/docs/use-integrations.doc.mjs +120 -0
- package/assets/docs/working-with-ai.doc.mjs +6 -2
- package/assets/templates/themes/butter/butterTheme.ts +4 -2
- package/assets/templates/themes/stone/stoneTheme.ts +4 -2
- package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
- package/authoring/debug/parse.d.mts +1 -1
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/integration/integration.doc.mjs +1 -1
- package/authoring/integration/type.ts +1 -1
- package/clients/cli/bin/astryx.mjs +7 -78
- package/clients/cli/command-result-coverage.test.mjs +6 -5
- package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
- package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
- package/clients/cli/commands/component.test.mjs +6 -6
- package/clients/cli/commands/docs.doc.mjs +2 -2
- package/clients/cli/commands/docs.mjs +1 -1
- package/clients/cli/commands/docs.test.mjs +14 -14
- package/clients/cli/commands/doctor-integration.test.mjs +49 -1
- package/clients/cli/commands/doctor.doc.mjs +1 -1
- package/clients/cli/commands/doctor.mjs +40 -0
- package/clients/cli/commands/doctor.test.mjs +65 -0
- package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
- package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
- package/clients/cli/commands/init.behavior.test.mjs +230 -1
- package/clients/cli/commands/init.doc.mjs +28 -9
- package/clients/cli/commands/init.flag-help.test.mjs +1 -0
- package/clients/cli/commands/init.mjs +2 -2
- package/clients/cli/commands/integration-check.test.mjs +48 -0
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/manifest.mjs +67 -0
- package/clients/cli/commands/outside-project.test.mjs +101 -1
- package/clients/cli/commands/postinstall.doc.mjs +23 -0
- package/clients/cli/commands/postinstall.mjs +31 -0
- package/clients/cli/commands/setup-nudge.test.mjs +78 -0
- package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
- package/clients/cli/commands/upgrade.doc.mjs +4 -2
- package/clients/cli/commands/upgrade.mjs +9 -2
- package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
- package/clients/cli/index.mjs +54 -94
- package/clients/cli/lib/component-format.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +12 -7
- package/clients/cli/lib/exit-codes.test.mjs +5 -0
- package/clients/cli/lib/manifest.test.mjs +12 -0
- package/clients/cli/lib/welcome-box.mjs +50 -0
- package/clients/cli/run.mjs +108 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +32 -7
- package/foundation/agent-docs/agent-doc-state.mjs +58 -9
- package/foundation/agent-docs/agent-docs.d.mts +100 -12
- package/foundation/agent-docs/agent-docs.mjs +1017 -105
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
- package/foundation/agent-docs/agent-docs.test.mjs +683 -39
- package/foundation/agent-docs/computer-agent-text.d.mts +39 -2
- package/foundation/agent-docs/computer-agent-text.mjs +135 -8
- package/foundation/agent-docs/computer-agent-text.test.mjs +99 -2
- package/foundation/config/project.mjs +20 -22
- package/foundation/config/project.test.mjs +56 -0
- package/foundation/discovery/authoring-self-docs.d.mts +7 -0
- package/foundation/discovery/authoring-self-docs.mjs +16 -4
- package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
- package/foundation/discovery/authoring-surface.d.mts +1 -1
- package/foundation/discovery/authoring-surface.mjs +2 -2
- package/foundation/discovery/authoring-surface.test.mjs +1 -1
- package/foundation/discovery/cli-self-docs.d.mts +2 -1
- package/foundation/discovery/cli-self-docs.mjs +4 -3
- package/foundation/discovery/cli-self-docs.test.mjs +2 -2
- package/foundation/discovery/component-discovery.d.mts +37 -0
- package/foundation/discovery/component-discovery.mjs +80 -5
- package/foundation/discovery/component-loader.d.mts +1 -1
- package/foundation/discovery/docs-discovery.mjs +14 -1
- package/foundation/discovery/module-exports.d.mts +41 -0
- package/foundation/discovery/module-exports.mjs +253 -0
- package/foundation/discovery/runner-allowlist.d.mts +2 -4
- package/foundation/discovery/runner-allowlist.mjs +2 -4
- package/foundation/discovery/runner-commands.d.mts +77 -0
- package/foundation/discovery/runner-commands.mjs +294 -0
- package/foundation/discovery/runner-commands.test.mjs +128 -0
- package/foundation/discovery/stray-pointers.test.mjs +1 -1
- package/foundation/discovery/template-adapter.mjs +18 -1
- package/foundation/discovery/template-needs.mjs +1 -44
- package/foundation/discovery/theme-discovery.mjs +147 -3
- package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
- package/foundation/doc-compiler/read.mjs +59 -1
- package/foundation/doc-compiler/read.test.mjs +11 -2
- package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
- package/foundation/doc-compiler/tree.d.mts +32 -6
- package/foundation/doc-compiler/tree.mjs +77 -43
- package/foundation/doc-compiler/tree.test.mjs +7 -7
- package/foundation/fs/paths.d.mts +70 -8
- package/foundation/fs/paths.mjs +556 -38
- package/foundation/fs/paths.test.mjs +430 -54
- package/foundation/fs/read-record.d.mts +18 -0
- package/foundation/fs/read-record.mjs +131 -0
- package/foundation/fs/read-record.test.mjs +77 -0
- package/foundation/integrations/autolink.d.mts +2 -1
- package/foundation/integrations/autolink.mjs +4 -13
- package/foundation/integrations/cli-peer-version.d.mts +36 -0
- package/foundation/integrations/cli-peer-version.mjs +132 -0
- package/foundation/integrations/cli-peer-version.test.mjs +354 -0
- package/foundation/integrations/computer-integrations.d.mts +6 -3
- package/foundation/integrations/computer-integrations.mjs +38 -9
- package/foundation/integrations/contribution-inventory.d.mts +15 -20
- package/foundation/integrations/contribution-inventory.mjs +41 -5
- package/foundation/integrations/exports-subpaths.d.mts +57 -0
- package/foundation/integrations/exports-subpaths.mjs +113 -0
- package/foundation/integrations/integrations.d.mts +27 -1
- package/foundation/integrations/integrations.mjs +61 -2
- package/foundation/integrations/public-imports.d.mts +118 -0
- package/foundation/integrations/public-imports.mjs +1769 -0
- package/foundation/integrations/public-imports.test.mjs +1793 -0
- package/foundation/integrations/validate-contributions.d.mts +115 -0
- package/foundation/integrations/validate-contributions.mjs +1168 -13
- package/foundation/release/cache.test.mjs +24 -21
- package/foundation/release/global-state.d.mts +8 -4
- package/foundation/release/global-state.mjs +4 -2
- package/foundation/release/handoff.d.mts +23 -4
- package/foundation/release/handoff.mjs +175 -8
- package/foundation/release/notices.d.mts +62 -8
- package/foundation/release/notices.mjs +136 -25
- package/foundation/release/notices.test.mjs +21 -0
- package/foundation/release/run-context.mjs +14 -0
- package/foundation/response/response-types.doc.mjs +1 -1
- package/foundation/route/route.d.mts +285 -0
- package/foundation/route/route.mjs +324 -0
- package/foundation/route/route.test.mjs +153 -0
- package/foundation/runtime/hosted-runtime.test.mjs +403 -0
- package/foundation/runtime/locked-versions.d.mts +32 -0
- package/foundation/runtime/locked-versions.mjs +65 -0
- package/foundation/runtime/package-root.d.mts +91 -0
- package/foundation/runtime/package-root.mjs +174 -0
- package/foundation/runtime/package-set.d.mts +62 -0
- package/foundation/runtime/package-set.mjs +130 -0
- package/foundation/runtime/package-set.test.mjs +432 -0
- package/foundation/text/string-utils.d.mts +2 -1
- package/foundation/text/string-utils.mjs +16 -5
- package/foundation/text/suggest-order.d.mts +72 -0
- package/foundation/text/suggest-order.mjs +363 -0
- package/foundation/text/suggest-order.test.mjs +259 -0
- package/host/door-conformance.test.mjs +274 -0
- package/host/index.d.ts +116 -0
- package/host/index.mjs +295 -0
- package/host/index.test.mjs +302 -0
- package/package.json +14 -9
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file One search term's score against one candidate: name, keyword, prose,
|
|
5
|
+
* and typo signals.
|
|
6
|
+
*
|
|
7
|
+
* Scoring is keyword + fuzzy ranking (NOT semantic / embeddings — that is a
|
|
8
|
+
* deliberate future follow-up). It reuses the same signal weighting as the
|
|
9
|
+
* component fuzzy resolver in lib/string-utils.mjs:
|
|
10
|
+
*
|
|
11
|
+
* 100 exact name match
|
|
12
|
+
* 95 name is the term's plural or stem form ("buttons" -> Button)
|
|
13
|
+
* 90 exact keyword match
|
|
14
|
+
* 88 keyword is the term's plural or stem form
|
|
15
|
+
* 80 name Levenshtein distance 1 (one-word lookups, words of 5+ letters)
|
|
16
|
+
* 70 keyword word prefix / distance 1 (distance: one-word lookups, 5+ letters)
|
|
17
|
+
* 60 name word prefix (>=4 chars, >=50% coverage)
|
|
18
|
+
* 60 exact weak-keyword match
|
|
19
|
+
* 50 description / prose mentions the term
|
|
20
|
+
* 45 usage guidance mentions the term
|
|
21
|
+
* 40 name Levenshtein distance 2 (one-word lookups, 8+ letters)
|
|
22
|
+
* 40 weak-keyword word prefix
|
|
23
|
+
* 30 keyword Levenshtein distance 2 (one-word lookups, 8+ letters)
|
|
24
|
+
* 20 name Levenshtein distance 3 (one-word lookups, 11+ letters)
|
|
25
|
+
*
|
|
26
|
+
* Name + keyword signals always outweigh description/prose, so an exact match
|
|
27
|
+
* sorts above an incidental mention.
|
|
28
|
+
*
|
|
29
|
+
* A term matches inside a name or keyword only at the start of one of its
|
|
30
|
+
* words: "dash" finds "dashboard" and "input" finds "TextInput", but "file"
|
|
31
|
+
* does not find "profile". Edit distance is typo tolerance, so it applies only
|
|
32
|
+
* to a one-word lookup, where a typo is the likely explanation, and only to
|
|
33
|
+
* words long enough that one edit rarely makes another real word. In a
|
|
34
|
+
* sentence, a near miss is usually a different word: "site" is not "side",
|
|
35
|
+
* "cable" is not "table".
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
|
|
39
|
+
import {
|
|
40
|
+
stem,
|
|
41
|
+
wordForms,
|
|
42
|
+
sameWord,
|
|
43
|
+
startsAWordOf,
|
|
44
|
+
joined,
|
|
45
|
+
isTypo,
|
|
46
|
+
} from './_words.mjs';
|
|
47
|
+
import {pluralOf} from './_query.mjs';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Score a single candidate against the search term across name, keywords,
|
|
51
|
+
* and prose signals. Returns the best (highest) score plus a human reason,
|
|
52
|
+
* or null if nothing matched above the floor.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} term - Lowercased search term.
|
|
55
|
+
* @param {object} candidate
|
|
56
|
+
* @param {string} candidate.name - Primary identifier (component/hook name, topic, template name).
|
|
57
|
+
* @param {string[]} [candidate.aliases] - Other names, scored like the name (a theme's display name).
|
|
58
|
+
* @param {string} [candidate.domain] - A component, hook, or template name
|
|
59
|
+
* also matches typed as words: `command palette` is CommandPalette.
|
|
60
|
+
* @param {string[]} [candidate.keywords] - Authored intent (componentsUsed, category words).
|
|
61
|
+
* @param {string[]} [candidate.weakKeywords] - Derived signal (components a page renders).
|
|
62
|
+
* @param {string} [candidate.description]
|
|
63
|
+
* @param {string[]} [candidate.prose] - Extra free-text blobs (doc section text, best practices).
|
|
64
|
+
* @param {string[]} [candidate.guidance] - Usage guidance (features, best practices) — scored a tier below description.
|
|
65
|
+
* @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.
|
|
66
|
+
* @returns {{score: number, reason: string, alias?: 'partial' | 'keyword'} | null}
|
|
67
|
+
* `alias` marks a hit that read the query's words joined.
|
|
68
|
+
*/
|
|
69
|
+
export function scoreCandidate(
|
|
70
|
+
term,
|
|
71
|
+
{
|
|
72
|
+
name,
|
|
73
|
+
aliases = [],
|
|
74
|
+
domain,
|
|
75
|
+
keywords = [],
|
|
76
|
+
weakKeywords = [],
|
|
77
|
+
description = '',
|
|
78
|
+
prose = [],
|
|
79
|
+
guidance = [],
|
|
80
|
+
},
|
|
81
|
+
{fuzzy = true, joins = true} = {},
|
|
82
|
+
) {
|
|
83
|
+
let best = 0;
|
|
84
|
+
let reason = '';
|
|
85
|
+
/** @type {'partial' | 'keyword' | false} */
|
|
86
|
+
let alias = false;
|
|
87
|
+
/**
|
|
88
|
+
* @param {number} score
|
|
89
|
+
* @param {string} why
|
|
90
|
+
* @param {'partial' | 'keyword' | false} [byAlias] - the hit reads the
|
|
91
|
+
* query's words joined, into part of a name or into a keyword
|
|
92
|
+
*/
|
|
93
|
+
const consider = (score, why, byAlias = false) => {
|
|
94
|
+
if (score > best) {
|
|
95
|
+
best = score;
|
|
96
|
+
reason = why;
|
|
97
|
+
alias = byAlias;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// ── Name signals ────────────────────────────────────────────────
|
|
102
|
+
// An alias is a name too: a theme answers to its display name as well as
|
|
103
|
+
// its slug.
|
|
104
|
+
for (const candidateName of [name, ...aliases.filter(Boolean)]) {
|
|
105
|
+
const nameLower = candidateName.toLowerCase();
|
|
106
|
+
// A placed guide's name is its route, and the route's last segment is its
|
|
107
|
+
// name too, as a flat topic's is: `codemods` is authoring/building-blocks/codemods.
|
|
108
|
+
const leafLower = nameLower.slice(nameLower.lastIndexOf('/') + 1);
|
|
109
|
+
|
|
110
|
+
// A plural of the name is the name: `integration` is the `integrations`
|
|
111
|
+
// guides, `tab` the `tabs` doc.
|
|
112
|
+
// A component, hook, or template name typed as words is its name:
|
|
113
|
+
// `command palette` is CommandPalette. A doc's name is a route or key,
|
|
114
|
+
// matched as written.
|
|
115
|
+
const spelled =
|
|
116
|
+
domain !== 'doc' &&
|
|
117
|
+
!/[\s_-]/.test(nameLower) &&
|
|
118
|
+
nameLower === term.replace(/\s+/g, '');
|
|
119
|
+
if (nameLower === term || leafLower === term || spelled) {
|
|
120
|
+
consider(100, 'exact name');
|
|
121
|
+
} else if (
|
|
122
|
+
joins &&
|
|
123
|
+
(domain === 'component' || domain === 'hook') &&
|
|
124
|
+
/\s/.test(term) &&
|
|
125
|
+
nameLower.startsWith(term.replace(/\s+/g, '')) &&
|
|
126
|
+
term.replace(/\s+/g, '').length / nameLower.length >= 0.75
|
|
127
|
+
) {
|
|
128
|
+
// Most of the name typed as words, cut short: `complex select` is
|
|
129
|
+
// ComplexSelector, ahead of a one-word keyword elsewhere.
|
|
130
|
+
consider(95, `name "${candidateName}" spelled`, 'partial');
|
|
131
|
+
} else if (pluralOf(nameLower, term) || pluralOf(term, nameLower)) {
|
|
132
|
+
// One point under the exact spelling, so the doc named `tokens` still
|
|
133
|
+
// outranks the Token component for `tokens`.
|
|
134
|
+
consider(99, 'plural of the name');
|
|
135
|
+
} else {
|
|
136
|
+
if (sameWord(term, nameLower)) consider(95, `name "${candidateName}"`);
|
|
137
|
+
// The term is a word of the name, or starts one: "input" in TextInput.
|
|
138
|
+
else if (startsAWordOf(term, candidateName)) {
|
|
139
|
+
consider(60, `name contains "${term}"`);
|
|
140
|
+
}
|
|
141
|
+
if (fuzzy) {
|
|
142
|
+
const dist = levenshteinDistance(term, nameLower);
|
|
143
|
+
if (isTypo(term, nameLower, dist)) {
|
|
144
|
+
consider(
|
|
145
|
+
dist === 1 ? 80 : dist === 2 ? 40 : 20,
|
|
146
|
+
`similar name (distance ${dist})`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ── Keyword signals ─────────────────────────────────────────────
|
|
154
|
+
const termJoined = joined(term);
|
|
155
|
+
for (const kw of keywords) {
|
|
156
|
+
const kwLower = String(kw).toLowerCase();
|
|
157
|
+
// A one-word keyword typed as separate words is the keyword: `number
|
|
158
|
+
// field` is `numberfield`. Only a
|
|
159
|
+
// lowercase keyword, one an author declares for a reader to type: a
|
|
160
|
+
// capitalized one names another entry (a block's `componentsUsed`). A
|
|
161
|
+
// doc's keywords include code terms, matched as written.
|
|
162
|
+
if (kwLower === term) {
|
|
163
|
+
consider(90, `keyword "${kw}"`);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (
|
|
167
|
+
joins &&
|
|
168
|
+
domain !== 'doc' &&
|
|
169
|
+
/\s/.test(term) &&
|
|
170
|
+
String(kw) === termJoined
|
|
171
|
+
) {
|
|
172
|
+
consider(90, `keyword "${kw}"`, 'keyword');
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (sameWord(term, kwLower)) {
|
|
176
|
+
consider(88, `keyword "${kw}"`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (startsAWordOf(term, kw)) consider(70, `keyword "${kw}"`);
|
|
180
|
+
if (fuzzy) {
|
|
181
|
+
const dist = levenshteinDistance(term, kwLower);
|
|
182
|
+
if (isTypo(term, kwLower, dist) && dist <= 2) {
|
|
183
|
+
consider(dist === 1 ? 70 : 30, `keyword "${kw}" (distance ${dist})`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ── Weak keyword signals (derived, not authored) ─────────────────
|
|
189
|
+
// Capped at 60 so one incidental component match cannot clear the
|
|
190
|
+
// confident-match gate on its own; it still counts toward multi-term
|
|
191
|
+
// coverage, which is where "this page renders that" is real evidence.
|
|
192
|
+
// No Levenshtein tier — fuzzy matching a derived signal is pure noise.
|
|
193
|
+
for (const kw of weakKeywords) {
|
|
194
|
+
const kwLower = String(kw).toLowerCase();
|
|
195
|
+
if (kwLower === term || sameWord(term, kwLower)) {
|
|
196
|
+
consider(60, `renders ${kw}`);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (startsAWordOf(term, kw)) consider(40, `renders ${kw}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ── Prose / description / guidance signals (stem-tolerant whole word) ──
|
|
203
|
+
// Match the term's stem as a whole word, tolerating plural/gerund suffixes
|
|
204
|
+
// so "chart" matches "charts" and "filter" matches "filtering".
|
|
205
|
+
if (term.length >= 3) {
|
|
206
|
+
// Any form of the term, with any common suffix: `spacing` finds
|
|
207
|
+
// "space" and "spaces", `tables` finds "table".
|
|
208
|
+
const roots = [...new Set([stem(term), ...wordForms(term)])]
|
|
209
|
+
.filter(f => f.length >= 3)
|
|
210
|
+
.map(f => f.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
211
|
+
const re = new RegExp(`\\b(?:${roots.join('|')})(s|es|ing|ed|ies)?\\b`);
|
|
212
|
+
if (description && re.test(description.toLowerCase())) {
|
|
213
|
+
consider(50, `description mentions "${term}"`);
|
|
214
|
+
} else {
|
|
215
|
+
let matchedProse = false;
|
|
216
|
+
for (const blob of prose) {
|
|
217
|
+
if (blob && re.test(String(blob).toLowerCase())) {
|
|
218
|
+
consider(50, `docs mention "${term}"`);
|
|
219
|
+
matchedProse = true;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// A tier below prose: guidance is what a component says about USING it,
|
|
224
|
+
// so the term appearing there is weaker evidence than the component's own
|
|
225
|
+
// summary. Only consulted when nothing stronger matched.
|
|
226
|
+
if (!matchedProse) {
|
|
227
|
+
for (const blob of guidance) {
|
|
228
|
+
if (blob && re.test(String(blob).toLowerCase())) {
|
|
229
|
+
consider(45, `guidance mentions "${term}"`);
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return best > 0 ? {score: best, reason, ...(alias ? {alias} : {})} : null;
|
|
238
|
+
}
|