@astryxdesign/cli 0.6.4 → 0.6.5-canary.01972bc
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 +56 -0
- package/README.md +103 -95
- package/api/build/_adapter.d.mts +36 -2
- package/api/build/_adapter.mjs +41 -10
- package/api/build/build.doc.mjs +8 -3
- package/api/build/build.test.mjs +60 -2
- package/api/build/kit/kit.mjs +109 -26
- package/api/build/kit/rank.d.mts +24 -8
- package/api/build/kit/rank.mjs +277 -97
- package/api/build/kit/rank.test.mjs +231 -48
- package/api/component/_adapter.d.mts +25 -0
- package/api/component/_adapter.mjs +59 -5
- package/api/component/component.d.mts +6 -3
- package/api/component/component.doc.mjs +37 -17
- package/api/component/component.mjs +249 -9
- package/api/component/component.type.d.mts +25 -0
- package/api/component/component.type.mjs +44 -0
- package/api/discover/_adapter.d.mts +114 -6
- package/api/discover/_adapter.mjs +372 -17
- package/api/discover/_adapter.test.mjs +215 -0
- package/api/discover/_catalog-view.d.mts +115 -0
- package/api/discover/_catalog-view.mjs +203 -0
- package/api/discover/_catalog-view.test.mjs +128 -0
- package/api/discover/detail/detail.d.mts +18 -6
- package/api/discover/detail/detail.mjs +67 -13
- package/api/discover/detail/detail.test.mjs +85 -0
- package/api/discover/detail/item/item.d.mts +26 -0
- package/api/discover/detail/item/item.mjs +78 -0
- package/api/discover/detail/item/item.test.mjs +73 -0
- package/api/discover/discover.d.mts +3 -9
- package/api/discover/discover.doc.mjs +61 -18
- package/api/discover/discover.mjs +220 -36
- package/api/discover/discover.test.mjs +11 -2
- package/api/discover/discover.type.d.mts +147 -8
- package/api/discover/discover.type.mjs +102 -12
- package/api/discover/list/list.d.mts +20 -6
- package/api/discover/list/list.mjs +45 -12
- package/api/discover/list/list.test.mjs +46 -0
- package/api/discover/search/search.d.mts +18 -16
- package/api/discover/search/search.mjs +102 -56
- package/api/discover/search/search.test.mjs +144 -10
- package/api/docs/_adapter.d.mts +8 -3
- package/api/docs/_adapter.mjs +14 -6
- package/api/docs/docOverlays.test.mjs +27 -1
- package/api/docs/docs.doc.mjs +2 -2
- package/api/docs/docs.test.mjs +54 -18
- package/api/docs/integration-tree.test.mjs +17 -0
- package/api/docs/integrationDocs.test.mjs +27 -5
- package/api/doctor/doctor.d.mts +8 -3
- package/api/doctor/doctor.doc.mjs +17 -8
- package/api/doctor/doctor.mjs +90 -9
- package/api/doctor/doctor.test.mjs +122 -10
- package/api/doctor/doctor.type.d.mts +1 -1
- package/api/doctor/doctor.type.mjs +1 -1
- package/api/error.d.mts +22 -0
- package/api/error.mjs +42 -0
- package/api/gap-report/gap-report.doc.mjs +19 -10
- package/api/hook/hook.doc.mjs +6 -3
- package/api/index.d.mts +1 -0
- package/api/index.mjs +5 -3
- package/api/init/init.doc.mjs +17 -12
- package/api/integration/add-contribution.d.mts +2 -1
- package/api/integration/add-contribution.mjs +7 -3
- package/api/integration/add-contribution.test.mjs +3 -3
- package/api/integration/add-helpers.d.mts +5 -2
- package/api/integration/add-helpers.mjs +36 -9
- package/api/integration/add-theme.mjs +266 -23
- package/api/integration/add-theme.test.mjs +247 -0
- package/api/integration/authoring-checks.mjs +12 -9
- package/api/integration/authoring-checks.type.d.mts +8 -0
- package/api/integration/authoring-checks.type.mjs +7 -3
- package/api/integration/integration-authoring.type.d.mts +4 -1
- package/api/integration/integration-authoring.type.mjs +6 -1
- package/api/integration/integrationAdd.doc.mjs +6 -0
- package/api/integration/integrationAddTheme.doc.mjs +10 -0
- package/api/integration/integrationComponentConflicts.doc.mjs +1 -1
- package/api/integration/integrationDocConflicts.doc.mjs +1 -1
- package/api/integration/integrationPackCheck.doc.mjs +3 -3
- package/api/integration/integrationTemplateConflicts.doc.mjs +1 -1
- package/api/integration/pack-check.lifecycle-output.test.mjs +107 -0
- package/api/integration/pack-check.mjs +92 -10
- package/api/integration/pack-check.test.mjs +140 -1
- package/api/integration/pack-check.type.mjs +1 -1
- package/api/integration/validate-integration.d.mts +4 -2
- package/api/integration/validate-integration.mjs +7 -2
- package/api/integration/validate-integration.test.mjs +55 -0
- package/api/integration/validate-integration.type.d.mts +5 -0
- package/api/integration/validate-integration.type.mjs +5 -1
- package/api/integration/validateIntegration.doc.mjs +1 -1
- package/api/json/assertResponse.doc.mjs +1 -1
- package/api/json/isError.doc.mjs +1 -1
- package/api/layout/expand/expand.mjs +12 -7
- package/api/layout/expand/expand.receipt.test.mjs +74 -0
- package/api/layout/layout.type.d.mts +1 -0
- package/api/layout/layout.type.mjs +1 -0
- package/api/layout/layoutExpand.doc.mjs +1 -1
- package/api/search/search.d.mts +51 -1
- package/api/search/search.doc.mjs +2 -2
- package/api/search/search.mjs +299 -17
- package/api/search/search.test.mjs +216 -18
- package/api/swizzle/copy/copy.mjs +66 -3
- package/api/swizzle/swizzle.doc.mjs +11 -5
- package/api/template/copy/copy.mjs +15 -9
- package/api/template/copy/copy.receipt.test.mjs +77 -0
- package/api/template/copy/copy.test.mjs +9 -0
- package/api/template/show/show.mjs +15 -4
- package/api/template/show/show.test.mjs +76 -0
- package/api/template/template-integration.test.mjs +14 -0
- package/api/template/template.d.mts +1 -1
- package/api/template/template.doc.mjs +8 -3
- package/api/template/template.mjs +1 -0
- package/api/template/template.type.d.mts +2 -0
- package/api/template/template.type.mjs +2 -0
- package/api/theme/add/add.mjs +17 -25
- package/api/theme/add/add.rollback.test.mjs +158 -0
- package/api/theme/add/add.staging.test.mjs +40 -23
- package/api/theme/build/build.d.mts +24 -0
- package/api/theme/build/build.family.test.mjs +7 -12
- package/api/theme/build/build.mjs +243 -26
- package/api/theme/build/build.project-core.test.mjs +165 -0
- package/api/theme/build/build.rollback.test.mjs +148 -0
- package/api/theme/generateTonalPalette.doc.mjs +1 -2
- package/api/theme/listThemes.doc.mjs +1 -1
- package/api/theme/themeAdd.doc.mjs +9 -10
- package/api/theme/themeBuild.doc.mjs +13 -13
- package/api/theme/themeList.doc.mjs +1 -1
- package/api/theme/themeListAvailable.doc.mjs +2 -1
- package/api/theme/themePaletteGenerate.doc.mjs +15 -8
- package/api/theme/themeTargets.doc.mjs +3 -2
- package/api/theme/themeTemplate.doc.mjs +2 -1
- package/api/upgrade/run/files-changed.test.mjs +111 -0
- package/api/upgrade/run/run.mjs +25 -6
- package/api/upgrade/run/run.test.mjs +45 -1
- package/api/upgrade/upgrade.doc.mjs +24 -22
- package/api/upgrade/upgrade.type.d.mts +1 -0
- package/api/upgrade/upgrade.type.mjs +3 -2
- package/assets/codemods/__tests__/runner.test.mjs +3 -1
- package/assets/codemods/file-count.test.mjs +163 -0
- package/assets/codemods/integration-runner.mjs +3 -3
- package/assets/codemods/runner.mjs +5 -4
- package/assets/docs/README.md +4 -2
- package/assets/docs/browser-support.doc.mjs +11 -11
- package/assets/docs/color.doc.mjs +8 -2
- package/assets/docs/elevation.doc.mjs +6 -4
- package/assets/docs/getting-started.doc.mjs +5 -16
- package/assets/docs/icons.doc.mjs +3 -21
- package/assets/docs/illustrations.doc.mjs +7 -15
- package/assets/docs/internationalization.doc.mjs +7 -5
- package/assets/docs/layout.doc.dense.mjs +130 -82
- package/assets/docs/layout.doc.mjs +133 -77
- package/assets/docs/migration.doc.mjs +19 -21
- package/assets/docs/motion.doc.mjs +16 -3
- package/assets/docs/principles.doc.dense.mjs +5 -5
- package/assets/docs/principles.doc.mjs +8 -0
- package/assets/docs/principles.doc.zh.mjs +6 -6
- package/assets/docs/shape.doc.mjs +8 -3
- package/assets/docs/spacing.doc.mjs +7 -2
- package/assets/docs/styling-libraries.doc.mjs +6 -2
- package/assets/docs/styling.doc.mjs +19 -23
- package/assets/docs/theme.doc.dense.mjs +58 -18
- package/assets/docs/theme.doc.mjs +57 -47
- package/assets/docs/theme.doc.zh.mjs +9 -8
- package/assets/docs/tokens.doc.dense.mjs +2 -2
- package/assets/docs/tokens.doc.mjs +389 -8
- package/assets/docs/tokens.doc.zh.mjs +2 -2
- package/assets/docs/tree/add-a-component.doc.mjs +75 -0
- package/assets/docs/tree/add-a-theme.doc.mjs +85 -0
- package/assets/docs/tree/add-a-topic.doc.mjs +144 -0
- package/assets/docs/tree/agent-guidance.doc.mjs +138 -0
- package/assets/docs/tree/block-template.doc.mjs +130 -0
- package/assets/docs/tree/build-the-template.doc.mjs +28 -0
- package/assets/docs/tree/building-blocks.doc.mjs +46 -0
- package/assets/docs/tree/check-your-docs.doc.mjs +137 -0
- package/assets/docs/tree/checks.doc.mjs +119 -0
- package/assets/docs/tree/codemods.doc.mjs +147 -0
- package/assets/docs/tree/component-family.doc.mjs +113 -0
- package/assets/docs/tree/component-imports.doc.mjs +69 -0
- package/assets/docs/tree/component-lookups.doc.mjs +149 -0
- package/assets/docs/tree/components.doc.mjs +23 -0
- package/assets/docs/tree/configuration.doc.mjs +23 -0
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +182 -0
- package/assets/docs/tree/define-the-theme.doc.mjs +118 -0
- package/assets/docs/tree/describe-the-component.doc.mjs +57 -0
- package/assets/docs/tree/docs.doc.mjs +21 -0
- package/assets/docs/tree/document-the-template.doc.mjs +28 -0
- package/assets/docs/tree/document-the-theme.doc.mjs +68 -0
- package/assets/docs/tree/export-template-assets.doc.mjs +147 -0
- package/assets/docs/tree/extend-or-replace.doc.mjs +103 -0
- package/assets/docs/tree/fonts-and-assets.doc.mjs +106 -0
- package/assets/docs/tree/generate-a-palette.doc.mjs +66 -0
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +105 -0
- package/assets/docs/tree/help.doc.mjs +16 -0
- package/assets/docs/tree/integrations.doc.mjs +25 -451
- package/assets/docs/tree/links.doc.mjs +98 -0
- package/assets/docs/tree/package-and-test.doc.mjs +32 -0
- package/assets/docs/tree/page-template.doc.mjs +71 -0
- package/assets/docs/tree/publishing.doc.mjs +111 -0
- package/assets/docs/tree/quick-start.doc.mjs +272 -0
- package/assets/docs/tree/replace-a-core-component.doc.mjs +104 -0
- package/assets/docs/tree/replace-a-core-template.doc.mjs +172 -0
- package/assets/docs/tree/sections-and-placement.doc.mjs +108 -0
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +59 -0
- package/assets/docs/tree/ship.doc.mjs +16 -0
- package/assets/docs/tree/short-and-findable.doc.mjs +108 -0
- package/assets/docs/tree/single-component.doc.mjs +165 -0
- package/assets/docs/tree/start-a-template.doc.mjs +143 -0
- package/assets/docs/tree/subcomponent.doc.mjs +115 -0
- package/assets/docs/tree/template-assets.doc.mjs +64 -0
- package/assets/docs/tree/template-doc-overview.doc.mjs +121 -0
- package/assets/docs/tree/template-fonts.doc.mjs +102 -0
- package/assets/docs/tree/template-grading-rubric.doc.mjs +452 -0
- package/assets/docs/tree/template-icons.doc.mjs +97 -0
- package/assets/docs/tree/template-images-media.doc.mjs +127 -0
- package/assets/docs/tree/template-styles.doc.mjs +93 -0
- package/assets/docs/tree/templates.doc.mjs +34 -0
- package/assets/docs/tree/test-in-an-app.doc.mjs +115 -0
- package/assets/docs/tree/test-template-in-app.doc.mjs +128 -0
- package/assets/docs/tree/themes.doc.mjs +39 -0
- package/assets/docs/tree/troubleshooting.doc.mjs +153 -0
- package/assets/docs/tree/upgrading.doc.mjs +103 -0
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +51 -0
- package/assets/docs/tree/verify-packed-template.doc.mjs +77 -0
- package/assets/docs/tree/versioning.doc.mjs +162 -0
- package/assets/docs/tree/write-good-templates.doc.mjs +64 -0
- package/assets/docs/tree/write-the-template-file.doc.mjs +154 -0
- package/assets/docs/typography.doc.mjs +24 -4
- package/assets/docs/working-with-ai.doc.mjs +30 -22
- package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
- package/assets/templates/pages/ai-chat/template.doc.mjs +16 -1
- package/assets/templates/pages/ai-chat-landing/template.doc.mjs +9 -1
- package/assets/templates/pages/blank/template.doc.mjs +3 -1
- package/assets/templates/pages/canvas-editor/template.doc.mjs +9 -1
- package/assets/templates/pages/centered-hero/template.doc.mjs +3 -1
- package/assets/templates/pages/checkout-wizard/template.doc.mjs +1 -0
- package/assets/templates/pages/classic-gallery/template.doc.mjs +3 -1
- package/assets/templates/pages/contact-form/template.doc.mjs +16 -1
- package/assets/templates/pages/dashboard/template.doc.mjs +15 -1
- package/assets/templates/pages/dashboard-alert-rail/template.doc.mjs +23 -1
- package/assets/templates/pages/dashboard-cohort-funnel/template.doc.mjs +10 -1
- package/assets/templates/pages/dashboard-comparison/template.doc.mjs +9 -1
- package/assets/templates/pages/dashboard-composition/template.doc.mjs +10 -1
- package/assets/templates/pages/dashboard-progress/template.doc.mjs +17 -1
- package/assets/templates/pages/dashboard-scorecard/template.doc.mjs +2 -1
- package/assets/templates/pages/detail-page/template.doc.mjs +8 -0
- package/assets/templates/pages/documentation/template.doc.mjs +10 -1
- package/assets/templates/pages/documentation-design/template.doc.mjs +10 -1
- package/assets/templates/pages/documentation-technical/template.doc.mjs +10 -1
- package/assets/templates/pages/editor/template.doc.mjs +9 -1
- package/assets/templates/pages/file-explorer/template.doc.mjs +3 -1
- package/assets/templates/pages/form-two-column/template.doc.mjs +17 -1
- package/assets/templates/pages/form-wizard/template.doc.mjs +14 -1
- package/assets/templates/pages/form-wizard-dialog/template.doc.mjs +1 -0
- package/assets/templates/pages/gallery-hero/template.doc.mjs +10 -1
- package/assets/templates/pages/ide/template.doc.mjs +9 -1
- package/assets/templates/pages/incident-console/template.doc.mjs +10 -1
- package/assets/templates/pages/kanban-board/template.doc.mjs +11 -1
- package/assets/templates/pages/library/template.doc.mjs +15 -1
- package/assets/templates/pages/login/template.doc.mjs +10 -1
- package/assets/templates/pages/login-card/template.doc.mjs +11 -1
- package/assets/templates/pages/login-split/template.doc.mjs +10 -1
- package/assets/templates/pages/login-sso/template.doc.mjs +10 -1
- package/assets/templates/pages/messaging-shell/template.doc.mjs +11 -1
- package/assets/templates/pages/mixed-gallery/template.doc.mjs +10 -1
- package/assets/templates/pages/payment-form/template.doc.mjs +3 -1
- package/assets/templates/pages/product-detail/template.doc.mjs +9 -1
- package/assets/templates/pages/product-gallery/template.doc.mjs +10 -1
- package/assets/templates/pages/settings/template.doc.mjs +3 -1
- package/assets/templates/pages/settings-dialog/template.doc.mjs +9 -1
- package/assets/templates/pages/settings-sidebar/template.doc.mjs +9 -1
- package/assets/templates/pages/shell-nav/template.doc.mjs +10 -1
- package/assets/templates/pages/shell-side-nav/template.doc.mjs +14 -1
- package/assets/templates/pages/shell-top-nav/template.doc.mjs +11 -1
- package/assets/templates/pages/side-gallery/template.doc.mjs +3 -1
- package/assets/templates/pages/table/template.doc.mjs +11 -1
- package/assets/templates/pages/table-filter/template.doc.mjs +21 -1
- package/assets/templates/pages/table-grouped/template.doc.mjs +15 -1
- package/assets/templates/pages/table-inbox/template.doc.mjs +18 -6
- package/assets/templates/pages/table-page/template.doc.mjs +20 -1
- package/assets/templates/pages/table-tree/template.doc.mjs +14 -1
- package/assets/templates/pages/theme-showcase/template.doc.mjs +10 -1
- package/assets/templates/pages/work-item-detail/template.doc.mjs +10 -0
- package/assets/templates/themes/butter/icons.tsx +2 -0
- package/assets/templates/themes/chocolate/icons.tsx +2 -0
- package/assets/templates/themes/gothic/icons.tsx +2 -0
- package/assets/templates/themes/matcha/icons.tsx +2 -0
- package/assets/templates/themes/neutral/icons.tsx +2 -0
- package/assets/templates/themes/stone/icons.tsx +2 -0
- package/assets/templates/themes/y2k/icons.tsx +2 -0
- package/authoring/config/config.doc.mjs +9 -1
- package/authoring/config/parse.d.mts +2 -0
- package/authoring/config/parse.mjs +19 -0
- package/authoring/config/parse.test.mjs +8 -0
- package/authoring/config/type.ts +11 -0
- package/authoring/discover/discover.doc.d.mts +13 -0
- package/authoring/discover/discover.doc.mjs +138 -0
- package/authoring/discover/parse.d.mts +24 -0
- package/authoring/discover/parse.mjs +128 -0
- package/authoring/discover/parse.test.mjs +124 -0
- package/authoring/discover/type.ts +87 -0
- package/authoring/doctypes/_schema.d.mts +3 -2
- package/authoring/doctypes/_schema.mjs +6 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +3 -3
- package/authoring/doctypes/base/type.ts +4 -2
- package/authoring/doctypes/component/component.doc.mjs +6 -0
- package/authoring/doctypes/component/type.ts +8 -0
- package/authoring/doctypes/reference/reference.doc.mjs +7 -0
- package/authoring/doctypes/reference/type.ts +5 -0
- package/authoring/doctypes/schema/schema.doc.mjs +2 -2
- package/authoring/doctypes/template/parse.d.mts +2 -0
- package/authoring/doctypes/template/parse.mjs +1 -0
- package/authoring/doctypes/template/parse.test.mjs +21 -0
- package/authoring/doctypes/template/template.doc.mjs +7 -1
- package/authoring/doctypes/template/type.ts +12 -2
- package/authoring/index.d.mts +1 -0
- package/authoring/index.d.ts +10 -0
- package/authoring/index.mjs +1 -0
- package/authoring/integration/integration.doc.mjs +12 -10
- package/clients/cli/commands/component/index.mjs +152 -55
- package/clients/cli/commands/component-batch.test.mjs +341 -0
- package/clients/cli/commands/component-ownership.test.mjs +89 -0
- package/clients/cli/commands/component.doc.mjs +27 -9
- package/clients/cli/commands/discover.doc.mjs +53 -9
- package/clients/cli/commands/discover.mjs +393 -118
- package/clients/cli/commands/discover.sources.test.mjs +267 -0
- package/clients/cli/commands/docs.doc.mjs +1 -1
- package/clients/cli/commands/docs.mjs +60 -17
- package/clients/cli/commands/docs.test.mjs +113 -24
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -2
- package/clients/cli/commands/doctor-integration.test.mjs +53 -0
- package/clients/cli/commands/doctor.doc.mjs +3 -1
- package/clients/cli/commands/doctor.mjs +53 -9
- package/clients/cli/commands/gap-report.doc.mjs +10 -9
- package/clients/cli/commands/init.doc.mjs +9 -6
- package/clients/cli/commands/integration-add.doc.mjs +17 -7
- package/clients/cli/commands/integration-authoring.test.mjs +70 -9
- package/clients/cli/commands/integration-pack.doc.mjs +5 -9
- package/clients/cli/commands/integration-real-world.test.mjs +1 -1
- package/clients/cli/commands/integration-verify.doc.mjs +22 -0
- package/clients/cli/commands/integration.doc.mjs +4 -4
- package/clients/cli/commands/integration.mjs +76 -43
- package/clients/cli/commands/layout-expand.doc.mjs +3 -1
- package/clients/cli/commands/layout.expand-receipt.test.mjs +94 -0
- package/clients/cli/commands/layout.mjs +16 -0
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/search.doc.mjs +10 -3
- package/clients/cli/commands/search.mjs +21 -2
- package/clients/cli/commands/search.test.mjs +21 -4
- package/clients/cli/commands/swizzle.doc.mjs +1 -1
- package/clients/cli/commands/template.copy-receipt.test.mjs +60 -0
- package/clients/cli/commands/template.doc.mjs +1 -1
- package/clients/cli/commands/template.mjs +19 -5
- package/clients/cli/commands/template.show-media.test.mjs +62 -0
- package/clients/cli/commands/text-json-parity.test.mjs +7 -1
- package/clients/cli/commands/theme-add.doc.mjs +1 -1
- package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -2
- package/clients/cli/commands/theme-palette.doc.mjs +1 -2
- package/clients/cli/commands/theme-targets.doc.mjs +2 -2
- package/clients/cli/commands/theme.doc.mjs +2 -1
- package/clients/cli/commands/upgrade.ascii-output.test.mjs +14 -0
- package/clients/cli/commands/upgrade.doc.mjs +62 -3
- package/clients/cli/commands/write-failure.test.mjs +175 -0
- package/clients/cli/index.mjs +28 -6
- package/clients/cli/lib/define-command.mjs +28 -4
- package/clients/cli/lib/define-command.test.mjs +54 -0
- package/clients/cli/lib/exit-codes.test.mjs +17 -1
- package/clients/cli/lib/json-shim.mjs +24 -14
- package/clients/cli/lib/manifest.mjs +48 -156
- package/clients/cli/lib/manifest.test.mjs +103 -9
- package/clients/cli/lib/parse-error-format.test.mjs +81 -0
- package/foundation/agent-docs/agent-docs.mjs +1 -1
- package/foundation/agent-docs/agent-docs.test.mjs +3 -2
- package/foundation/discovery/authoring-self-docs.mjs +1 -0
- package/foundation/discovery/authoring-self-docs.test.mjs +6 -2
- package/foundation/discovery/cli-self-docs.mjs +16 -2
- package/foundation/discovery/cli-self-docs.test.mjs +20 -0
- package/foundation/discovery/docs-discovery.mjs +5 -1
- package/foundation/discovery/docs-discovery.test.mjs +21 -0
- package/foundation/discovery/docs-section-key.d.mts +1 -1
- package/foundation/discovery/docs-section-key.mjs +1 -1
- package/foundation/discovery/template-adapter.d.mts +14 -0
- package/foundation/discovery/template-adapter.fixture-refs.test.mjs +37 -1
- package/foundation/discovery/template-adapter.mjs +21 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +5 -4
- package/foundation/doc-compiler/inputs.test.mjs +0 -1
- package/foundation/doc-compiler/tree.d.mts +4 -0
- package/foundation/doc-compiler/tree.mjs +6 -1
- package/foundation/doc-compiler/tree.test.mjs +65 -14
- package/foundation/integrations/cli-requirement.d.mts +75 -11
- package/foundation/integrations/cli-requirement.mjs +120 -23
- package/foundation/integrations/cli-requirement.test.mjs +141 -9
- package/foundation/integrations/contribution-inventory.mjs +1 -1
- package/foundation/integrations/integrations.d.mts +14 -1
- package/foundation/integrations/integrations.mjs +41 -1
- package/foundation/integrations/integrations.test.mjs +31 -0
- package/foundation/response/batch.type.d.mts +33 -0
- package/foundation/response/batch.type.mjs +34 -0
- package/foundation/response/error-codes.doc.mjs +6 -8
- package/foundation/response/error-codes.test.mjs +30 -5
- package/foundation/response/response-types.doc.d.mts +5 -4
- package/foundation/response/response-types.doc.mjs +49 -19
- package/foundation/response/response-types.doc.test.mjs +23 -0
- package/foundation/response/response.doc.mjs +11 -10
- package/package.json +9 -9
- package/assets/docs/tree/integrations.test.mjs +0 -62
- package/assets/docs/tree/writing-docs.doc.mjs +0 -286
package/api/build/kit/rank.mjs
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file The page ranker behind `build`'s START: which page template an idea
|
|
5
|
-
* should start from.
|
|
5
|
+
* should start from, and whether the idea asks for a page at all.
|
|
6
6
|
*
|
|
7
|
-
* @input A free-text idea
|
|
8
|
-
* name, description, `Family - Variant` category)
|
|
9
|
-
*
|
|
7
|
+
* @input A free-text idea, the project's ready page templates (id, display
|
|
8
|
+
* name, description, keywords, `Family - Variant` category) and its
|
|
9
|
+
* components (name, keywords), all read from each item's own descriptor.
|
|
10
10
|
* @output Every template, ranked, with the query terms it matched and whether
|
|
11
|
-
* the idea names its family; `
|
|
11
|
+
* the idea names its family; `ideaKind`, whether the idea asks for a page, a
|
|
12
|
+
* part of one, or a change to a page the builder has; `pickStart` turns both
|
|
13
|
+
* into a template or null.
|
|
12
14
|
* @position Beside kit.mjs (api/build/kit/). Search ranks components, docs,
|
|
13
15
|
* blocks and pages against short lookups; this ranks only page templates,
|
|
14
16
|
* against the long descriptions builders actually write ("ops dashboard with
|
|
@@ -36,8 +38,27 @@
|
|
|
36
38
|
* next one counts half, unless the template names the same pair
|
|
37
39
|
* ("executive summary").
|
|
38
40
|
* - The family base. A template whose id is its family's name (`dashboard`,
|
|
39
|
-
* `settings`) is that family's default
|
|
40
|
-
*
|
|
41
|
+
* `settings`) is that family's default. A variant displaces it only with two
|
|
42
|
+
* matched terms of its own ("a small comparison note" does not make a
|
|
43
|
+
* dashboard the comparison dashboard), and a base too weak to start on its
|
|
44
|
+
* own displaces no variant ("a funnel for a dashboard" is the funnel).
|
|
45
|
+
*
|
|
46
|
+
* Parts (spec:AST-048/FR3). "A date range picker" asks for a part of a page,
|
|
47
|
+
* not a page, and the system's own components say what a part is: an idea
|
|
48
|
+
* whose head noun is a word of a component's name or keywords, Core's or an
|
|
49
|
+
* integration's, asks for that part, unless the noun is a family word ("a data
|
|
50
|
+
* table") or the idea lists a page's worth of pieces. Words search drops as
|
|
51
|
+
* stopwords ("page", "screen", "app", "view") name no component, so "a calendar
|
|
52
|
+
* page" asks for a page and "a calendar" for a part. A part starts from the
|
|
53
|
+
* base template of the family the idea names ("an empty state for a settings
|
|
54
|
+
* page"), else from the app shell. An idea that changes a page or part the
|
|
55
|
+
* builder already has starts from the app shell too: that page is the
|
|
56
|
+
* builder's to keep (FR9), and no template scaffolds it. "Existing" marks one
|
|
57
|
+
* when its phrase names a page family or a component ("add a column to the
|
|
58
|
+
* existing table"), unless the idea asks for a new page ("a new dashboard like
|
|
59
|
+
* the existing dashboard", "clone the existing dashboard as a new page"). A
|
|
60
|
+
* bare "existing" phrase that names a page ("existing reports dashboard with a
|
|
61
|
+
* date filter") reads as the builder's own page.
|
|
41
62
|
*
|
|
42
63
|
* Family words come from the templates' own ids — a word in the ids of two or
|
|
43
64
|
* more templates of one family, plus the family's name when a template carries
|
|
@@ -50,79 +71,68 @@ import {stem, STOPWORDS, SYNONYMS} from '../../search/search.mjs';
|
|
|
50
71
|
|
|
51
72
|
/**
|
|
52
73
|
* How much a term counts by where the template names it. The id and category
|
|
53
|
-
* are the author's own label for what the page is; the
|
|
54
|
-
*
|
|
74
|
+
* are the author's own label for what the page is; its keywords name the ideas
|
|
75
|
+
* it serves; its description describes the layout.
|
|
55
76
|
*/
|
|
56
77
|
const FIELD_WEIGHT = {
|
|
57
78
|
id: 3,
|
|
58
79
|
variant: 3,
|
|
59
80
|
family: 2,
|
|
60
81
|
display: 2,
|
|
61
|
-
|
|
62
|
-
|
|
82
|
+
keywords: 2,
|
|
83
|
+
description: 1,
|
|
63
84
|
};
|
|
64
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* A synonym hit counts half a direct hit: a synonym says the idea is near the
|
|
87
|
+
* page, not that it names it.
|
|
88
|
+
*/
|
|
65
89
|
const SYNONYM_SHARE = 0.5;
|
|
66
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* A container word ("in a modal") counts double: it names the page's frame,
|
|
92
|
+
* which is what a template is.
|
|
93
|
+
*/
|
|
67
94
|
const CONTAINER = 2;
|
|
68
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* A word that only modifies another ("product" in "product response") counts
|
|
97
|
+
* half: it describes its head, not the page.
|
|
98
|
+
*/
|
|
69
99
|
const MODIFIER = 0.5;
|
|
70
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* Added when the idea's head names the template's family: more than any one
|
|
102
|
+
* word scores (an id word only one template carries is worth about ten), so the
|
|
103
|
+
* head's family outranks a rarer word among the parts.
|
|
104
|
+
*/
|
|
71
105
|
const HEAD_FAMILY = 12;
|
|
72
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* Added when the family is named anywhere else in the idea: about a description
|
|
108
|
+
* word, enough to settle a near tie.
|
|
109
|
+
*/
|
|
73
110
|
const BODY_FAMILY = 2;
|
|
74
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* Added to a family's base template when the idea names that family: settles a
|
|
113
|
+
* near tie toward the family's default page.
|
|
114
|
+
*/
|
|
75
115
|
const FAMILY_BASE = 2;
|
|
76
116
|
/**
|
|
77
117
|
* The least a start must score, and the evidence it needs: two matched terms,
|
|
78
118
|
* or the idea naming its family. One rare word alone is how a tic-tac-toe game
|
|
79
|
-
* board became a kanban board
|
|
119
|
+
* board became a kanban board, and it is also too little for a variant to
|
|
120
|
+
* displace its family's base template.
|
|
80
121
|
*/
|
|
81
122
|
const START_SCORE = 10;
|
|
82
123
|
const START_TERMS = 2;
|
|
124
|
+
/**
|
|
125
|
+
* How many listed pieces make an idea a page: a part is one thing with a detail
|
|
126
|
+
* or two ("a status pill with a tooltip"), while three pieces, two commas
|
|
127
|
+
* apart, describe a page.
|
|
128
|
+
*/
|
|
129
|
+
const PAGE_PIECES = 3;
|
|
83
130
|
|
|
84
131
|
/**
|
|
85
132
|
* Words search drops that name layout: "side navigation", "side by side".
|
|
86
133
|
*/
|
|
87
134
|
const LAYOUT_WORDS = new Set(['side']);
|
|
88
135
|
|
|
89
|
-
/** Filler that search keeps but that says nothing about a page's layout. */
|
|
90
|
-
const FILLER = new Set([
|
|
91
|
-
'per',
|
|
92
|
-
'each',
|
|
93
|
-
'every',
|
|
94
|
-
'using',
|
|
95
|
-
'via',
|
|
96
|
-
'into',
|
|
97
|
-
'onto',
|
|
98
|
-
'about',
|
|
99
|
-
'above',
|
|
100
|
-
'below',
|
|
101
|
-
'across',
|
|
102
|
-
'within',
|
|
103
|
-
'without',
|
|
104
|
-
'between',
|
|
105
|
-
'plus',
|
|
106
|
-
'also',
|
|
107
|
-
'then',
|
|
108
|
-
'them',
|
|
109
|
-
'they',
|
|
110
|
-
'which',
|
|
111
|
-
'while',
|
|
112
|
-
'when',
|
|
113
|
-
'all',
|
|
114
|
-
'any',
|
|
115
|
-
'new',
|
|
116
|
-
'use',
|
|
117
|
-
'used',
|
|
118
|
-
'show',
|
|
119
|
-
'shows',
|
|
120
|
-
'showing',
|
|
121
|
-
'display',
|
|
122
|
-
'displays',
|
|
123
|
-
'displaying',
|
|
124
|
-
]);
|
|
125
|
-
|
|
126
136
|
/**
|
|
127
137
|
* Where an idea's head ends: its first clause, before the parts it lists.
|
|
128
138
|
*/
|
|
@@ -142,6 +152,24 @@ const OVERLAY_FRAMES = new Set([
|
|
|
142
152
|
'overlay',
|
|
143
153
|
]);
|
|
144
154
|
|
|
155
|
+
/**
|
|
156
|
+
* The word that marks a page or part the builder already has, when its phrase
|
|
157
|
+
* names one (see `changesExistingPage`).
|
|
158
|
+
*/
|
|
159
|
+
const EXISTING = /\bexisting\b/i;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The word that marks an idea asking for a new page ("a new dashboard", "as a
|
|
163
|
+
* new page"), which is never a change to one the builder has.
|
|
164
|
+
*/
|
|
165
|
+
const NEW = /\bnew\b/;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The family whose templates are app chrome rather than page content: the
|
|
169
|
+
* explicit `Shell -` category (architecture:template-authoring/INV7).
|
|
170
|
+
*/
|
|
171
|
+
const SHELL_FAMILY = 'Shell';
|
|
172
|
+
|
|
145
173
|
/** A container phrase: "in a modal", "inside the side panel". */
|
|
146
174
|
const CONTAINER_PHRASE =
|
|
147
175
|
/\b(?:in|inside|within)\s+(?:a|an|the)\s+([a-z-]+)(?:\s+([a-z-]+))?/gi;
|
|
@@ -155,12 +183,11 @@ const PHRASE_END =
|
|
|
155
183
|
|
|
156
184
|
/** @param {string} t */
|
|
157
185
|
const isContentWord = t =>
|
|
158
|
-
t.length >= 2 &&
|
|
159
|
-
(LAYOUT_WORDS.has(t) || (!STOPWORDS.has(t) && !FILLER.has(t)));
|
|
186
|
+
t.length >= 2 && (LAYOUT_WORDS.has(t) || !STOPWORDS.has(t));
|
|
160
187
|
|
|
161
188
|
/**
|
|
162
|
-
* Content terms of a text: lowercase alphanumeric words, stopwords
|
|
163
|
-
*
|
|
189
|
+
* Content terms of a text: lowercase alphanumeric words, stopwords removed,
|
|
190
|
+
* stemmed.
|
|
164
191
|
* @param {string} text
|
|
165
192
|
* @returns {string[]}
|
|
166
193
|
*/
|
|
@@ -262,8 +289,44 @@ const SYNONYMS_OF = (() => {
|
|
|
262
289
|
|
|
263
290
|
/**
|
|
264
291
|
* @typedef {import('../_adapter.mjs').PageTemplate} PageTemplate
|
|
265
|
-
* @typedef {
|
|
292
|
+
* @typedef {import('../_adapter.mjs').ComponentWords} ComponentWords
|
|
293
|
+
* @typedef {{name: string, score: number, hits: number, familyNamed: boolean, containerMatched: boolean, family: string, base: boolean, matched: Set<string>}} RankedPage
|
|
294
|
+
* @typedef {'page' | 'part' | 'edit'} IdeaKind
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
/** @param {PageTemplate} page */
|
|
298
|
+
const familyOf = page => (page.category.split(' - ')[0] ?? '').trim();
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Family words, from the templates' own ids: a word in the ids of two or more
|
|
302
|
+
* templates of one family, plus the family's name when a template carries it.
|
|
303
|
+
* Each word maps to its family.
|
|
304
|
+
* @param {PageTemplate[]} pages
|
|
305
|
+
* @returns {Map<string, string>}
|
|
266
306
|
*/
|
|
307
|
+
function familyWordsOf(pages) {
|
|
308
|
+
/** @type {Map<string, Map<string, number>>} */
|
|
309
|
+
const idWords = new Map();
|
|
310
|
+
for (const page of pages) {
|
|
311
|
+
const family = familyOf(page);
|
|
312
|
+
const counts = idWords.get(family) ?? new Map();
|
|
313
|
+
for (const w of new Set(page.name.split('-'))) {
|
|
314
|
+
if (w.length >= 3) counts.set(stem(w), (counts.get(stem(w)) ?? 0) + 1);
|
|
315
|
+
}
|
|
316
|
+
idWords.set(family, counts);
|
|
317
|
+
}
|
|
318
|
+
/** @type {Map<string, string>} */
|
|
319
|
+
const familyOfWord = new Map();
|
|
320
|
+
for (const [family, counts] of idWords) {
|
|
321
|
+
const heads = [...counts].filter(([, c]) => c >= 2).map(([w]) => w);
|
|
322
|
+
const name = normalized(family).split(' ').pop() ?? '';
|
|
323
|
+
if (name.length >= 3 && counts.has(stem(name))) heads.push(stem(name));
|
|
324
|
+
for (const head of heads) {
|
|
325
|
+
if (!familyOfWord.has(head)) familyOfWord.set(head, family);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return familyOfWord;
|
|
329
|
+
}
|
|
267
330
|
|
|
268
331
|
/**
|
|
269
332
|
* Rank page templates against an idea, best first. Ties go to the template
|
|
@@ -276,20 +339,15 @@ const SYNONYMS_OF = (() => {
|
|
|
276
339
|
export function rankPages(query, pages) {
|
|
277
340
|
const docs = pages.map(page => {
|
|
278
341
|
const [family = '', ...variantParts] = page.category.split(' - ');
|
|
279
|
-
const sentences = page.description.trim().split(/(?<=[.!?])\s+/);
|
|
280
|
-
const intent = sentences.length > 1 ? sentences[sentences.length - 1] : '';
|
|
281
|
-
const body =
|
|
282
|
-
sentences.length > 1
|
|
283
|
-
? sentences.slice(0, -1).join(' ')
|
|
284
|
-
: page.description;
|
|
285
342
|
/** @type {Record<keyof typeof FIELD_WEIGHT, string>} */
|
|
286
343
|
const fields = {
|
|
287
344
|
id: page.name.replace(/-/g, ' '),
|
|
288
345
|
variant: variantParts.join(' - '),
|
|
289
346
|
family,
|
|
290
347
|
display: page.displayName,
|
|
291
|
-
|
|
292
|
-
|
|
348
|
+
// Each keyword is its own phrase: a pair never spans two of them.
|
|
349
|
+
keywords: (page.keywords ?? []).join(', '),
|
|
350
|
+
description: page.description,
|
|
293
351
|
};
|
|
294
352
|
/** @type {Map<string, number>} */
|
|
295
353
|
const bag = new Map();
|
|
@@ -320,26 +378,7 @@ export function rankPages(query, pages) {
|
|
|
320
378
|
return d ? Math.log(1 + (n - d + 0.5) / (d + 0.5)) : 0;
|
|
321
379
|
};
|
|
322
380
|
|
|
323
|
-
|
|
324
|
-
/** @type {Map<string, Map<string, number>>} */
|
|
325
|
-
const idWords = new Map();
|
|
326
|
-
for (const {page, family} of docs) {
|
|
327
|
-
const counts = idWords.get(family) ?? new Map();
|
|
328
|
-
for (const w of new Set(page.name.split('-'))) {
|
|
329
|
-
if (w.length >= 3) counts.set(stem(w), (counts.get(stem(w)) ?? 0) + 1);
|
|
330
|
-
}
|
|
331
|
-
idWords.set(family, counts);
|
|
332
|
-
}
|
|
333
|
-
/** @type {Map<string, string>} */
|
|
334
|
-
const familyOfWord = new Map();
|
|
335
|
-
for (const [family, counts] of idWords) {
|
|
336
|
-
const heads = [...counts].filter(([, c]) => c >= 2).map(([w]) => w);
|
|
337
|
-
const name = normalized(family).split(' ').pop() ?? '';
|
|
338
|
-
if (name.length >= 3 && counts.has(stem(name))) heads.push(stem(name));
|
|
339
|
-
for (const head of heads) {
|
|
340
|
-
if (!familyOfWord.has(head)) familyOfWord.set(head, family);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
381
|
+
const familyOfWord = familyWordsOf(pages);
|
|
343
382
|
/** @param {string[]} ts */
|
|
344
383
|
const familiesIn = ts =>
|
|
345
384
|
new Set(ts.filter(t => familyOfWord.has(t)).map(t => familyOfWord.get(t)));
|
|
@@ -352,11 +391,13 @@ export function rankPages(query, pages) {
|
|
|
352
391
|
const modifiers = modifiersOf(query);
|
|
353
392
|
const containers = containersOf(query);
|
|
354
393
|
|
|
355
|
-
|
|
394
|
+
const ranked = docs
|
|
356
395
|
.map(({page, family, bag, pairs}) => {
|
|
357
396
|
let score = 0;
|
|
358
397
|
let hits = 0;
|
|
359
398
|
let containerMatched = false;
|
|
399
|
+
/** @type {Set<string>} */
|
|
400
|
+
const matched = new Set();
|
|
360
401
|
for (const t of queryTerms) {
|
|
361
402
|
// A modifier is discounted where the template names it outright; a
|
|
362
403
|
// synonym hit is already discounted by SYNONYM_SHARE.
|
|
@@ -378,16 +419,25 @@ export function rankPages(query, pages) {
|
|
|
378
419
|
if (value > 0) {
|
|
379
420
|
score += value;
|
|
380
421
|
hits++;
|
|
422
|
+
matched.add(t);
|
|
381
423
|
if (containers.has(t)) containerMatched = true;
|
|
382
424
|
}
|
|
383
425
|
}
|
|
384
426
|
const familyNamed = namedFamilies.has(family);
|
|
385
427
|
if (headFamilies.has(family)) score += HEAD_FAMILY;
|
|
386
428
|
else if (familyNamed) score += BODY_FAMILY;
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
429
|
+
const base = normalized(page.name) === normalized(family);
|
|
430
|
+
if (familyNamed && base) score += FAMILY_BASE;
|
|
431
|
+
return {
|
|
432
|
+
name: page.name,
|
|
433
|
+
score,
|
|
434
|
+
hits,
|
|
435
|
+
familyNamed,
|
|
436
|
+
containerMatched,
|
|
437
|
+
family,
|
|
438
|
+
base,
|
|
439
|
+
matched,
|
|
440
|
+
};
|
|
391
441
|
})
|
|
392
442
|
.sort(
|
|
393
443
|
(a, b) =>
|
|
@@ -395,6 +445,123 @@ export function rankPages(query, pages) {
|
|
|
395
445
|
a.name.split('-').length - b.name.split('-').length ||
|
|
396
446
|
a.name.localeCompare(b.name),
|
|
397
447
|
);
|
|
448
|
+
return baseFirst(ranked);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Put a named family's base template ahead of the variant that outranks it,
|
|
453
|
+
* unless the variant matched START_TERMS terms the base did not, or the base
|
|
454
|
+
* scores too little to start on its own.
|
|
455
|
+
* @param {RankedPage[]} ranked
|
|
456
|
+
* @returns {RankedPage[]}
|
|
457
|
+
*/
|
|
458
|
+
function baseFirst(ranked) {
|
|
459
|
+
const top = ranked[0];
|
|
460
|
+
if (!top || top.base || !top.familyNamed) return ranked;
|
|
461
|
+
const base = ranked.find(r => r.base && r.family === top.family);
|
|
462
|
+
if (!base || base.score < START_SCORE) return ranked;
|
|
463
|
+
const own = [...top.matched].filter(t => !base.matched.has(t)).length;
|
|
464
|
+
return own >= START_TERMS
|
|
465
|
+
? ranked
|
|
466
|
+
: [base, ...ranked.filter(r => r !== base)];
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* What an idea asks for (spec:AST-048/FR3): a whole `page`; a `part` of one,
|
|
471
|
+
* when its head noun names one of the system's components and it lists fewer
|
|
472
|
+
* than PAGE_PIECES pieces; or an `edit` of a page the builder already has.
|
|
473
|
+
*
|
|
474
|
+
* @param {string} query
|
|
475
|
+
* @param {PageTemplate[]} pages
|
|
476
|
+
* @param {ComponentWords[]} components
|
|
477
|
+
* @returns {IdeaKind}
|
|
478
|
+
*/
|
|
479
|
+
export function ideaKind(query, pages, components) {
|
|
480
|
+
const text = String(query);
|
|
481
|
+
const familyWords = familyWordsOf(pages);
|
|
482
|
+
if (changesExistingPage(text, familyWords, components)) return 'edit';
|
|
483
|
+
// The head's last word, page words included: "calendar" is the noun of "a
|
|
484
|
+
// calendar", "page" the noun of "a calendar page". An overlay frame names
|
|
485
|
+
// where the thing lives, not the thing: "drafts" is the noun of "drafts in
|
|
486
|
+
// a modal".
|
|
487
|
+
const head = (text.split(HEAD_END)[0] ?? '').replace(CONTAINER_PHRASE, m =>
|
|
488
|
+
containersOf(m).size > 0 ? ' ' : m,
|
|
489
|
+
);
|
|
490
|
+
const words = (head.toLowerCase().match(/[a-z0-9]+/g) ?? []).filter(
|
|
491
|
+
w => w.length >= 2,
|
|
492
|
+
);
|
|
493
|
+
const noun = stem(words[words.length - 1] ?? '');
|
|
494
|
+
if (familyWords.has(noun)) return 'page';
|
|
495
|
+
const pieces = (text.match(/,/g) ?? []).length + 1;
|
|
496
|
+
if (pieces >= PAGE_PIECES) return 'page';
|
|
497
|
+
return components.some(c => componentTerms(c).includes(noun))
|
|
498
|
+
? 'part'
|
|
499
|
+
: 'page';
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Whether an idea changes a page or part the builder already has: "existing"
|
|
504
|
+
* in the same phrase as a word that names a family of page templates or one of
|
|
505
|
+
* the system's components ("the existing incidents table", "the existing
|
|
506
|
+
* banner"). A new page "inspired by the existing one", or "existing users" on a
|
|
507
|
+
* new page, names neither, and an idea that asks for a new page is no change
|
|
508
|
+
* whatever it names.
|
|
509
|
+
* @param {string} text
|
|
510
|
+
* @param {Map<string, string>} familyWords
|
|
511
|
+
* @param {ComponentWords[]} components
|
|
512
|
+
* @returns {boolean}
|
|
513
|
+
*/
|
|
514
|
+
function changesExistingPage(text, familyWords, components) {
|
|
515
|
+
const componentWords = new Set(components.flatMap(nameTerms));
|
|
516
|
+
const phrases = text.toLowerCase().split(PHRASE_END);
|
|
517
|
+
if (asksNewPage(phrases, familyWords)) return false;
|
|
518
|
+
return phrases.some(phrase => {
|
|
519
|
+
const at = phrase.search(EXISTING);
|
|
520
|
+
return (
|
|
521
|
+
at >= 0 &&
|
|
522
|
+
terms(phrase.slice(at)).some(
|
|
523
|
+
t => familyWords.has(t) || componentWords.has(t),
|
|
524
|
+
)
|
|
525
|
+
);
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Whether an idea asks for a new page: "new" before a word that names a family
|
|
531
|
+
* of page templates ("a new dashboard"), or before only words search drops,
|
|
532
|
+
* such as "page" ("as a new page"). "A new column" asks for a part.
|
|
533
|
+
* @param {string[]} phrases
|
|
534
|
+
* @param {Map<string, string>} familyWords
|
|
535
|
+
* @returns {boolean}
|
|
536
|
+
*/
|
|
537
|
+
function asksNewPage(phrases, familyWords) {
|
|
538
|
+
return phrases.some(phrase => {
|
|
539
|
+
const at = phrase.search(NEW);
|
|
540
|
+
if (at < 0) return false;
|
|
541
|
+
const after = terms(phrase.slice(at + 'new'.length));
|
|
542
|
+
return after.length === 0 || familyWords.has(after[0]);
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* The words of a component's name: "DateRangeInput" is date, range, input.
|
|
548
|
+
* @param {ComponentWords} component
|
|
549
|
+
* @returns {string[]}
|
|
550
|
+
*/
|
|
551
|
+
function nameTerms(component) {
|
|
552
|
+
return terms(component.name.replace(/([a-z0-9])([A-Z])/g, '$1 $2'));
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* The terms a component answers to: the words of its name and of its keywords.
|
|
557
|
+
* @param {ComponentWords} component
|
|
558
|
+
* @returns {string[]}
|
|
559
|
+
*/
|
|
560
|
+
function componentTerms(component) {
|
|
561
|
+
return [
|
|
562
|
+
...nameTerms(component),
|
|
563
|
+
...component.keywords.flatMap(keyword => terms(keyword)),
|
|
564
|
+
];
|
|
398
565
|
}
|
|
399
566
|
|
|
400
567
|
/**
|
|
@@ -416,14 +583,27 @@ export function pickAlternatives(ranked, startName, count = 2) {
|
|
|
416
583
|
}
|
|
417
584
|
|
|
418
585
|
/**
|
|
419
|
-
* The template to start from, or null
|
|
420
|
-
* evidence to lead
|
|
421
|
-
*
|
|
586
|
+
* The template to start from, or null for the kit's neutral app shell. A page
|
|
587
|
+
* needs evidence to lead: two matched terms, the idea naming the template's
|
|
588
|
+
* family, or its container. A part starts from the base template of the family
|
|
589
|
+
* the idea places it in, else from the app shell (spec:AST-048/FR3); an edit of
|
|
590
|
+
* a page the builder already has starts from the app shell (FR9). Either way,
|
|
591
|
+
* the app shell is the shell template the idea describes when one leads.
|
|
422
592
|
*
|
|
423
593
|
* @param {RankedPage[]} ranked
|
|
594
|
+
* @param {IdeaKind} [kind]
|
|
424
595
|
* @returns {RankedPage | null}
|
|
425
596
|
*/
|
|
426
|
-
export function pickStart(ranked) {
|
|
597
|
+
export function pickStart(ranked, kind = 'page') {
|
|
598
|
+
if (kind !== 'page') {
|
|
599
|
+
const host = kind === 'part' && ranked.find(r => r.base && r.familyNamed);
|
|
600
|
+
if (host) return host;
|
|
601
|
+
// Otherwise the app shell (FR2): the shell template the idea describes
|
|
602
|
+
// when one leads ("a frame with sidebar navigation"), else none, for the
|
|
603
|
+
// kit's neutral fallback.
|
|
604
|
+
const lead = pickStart(ranked);
|
|
605
|
+
return lead?.family === SHELL_FAMILY ? lead : null;
|
|
606
|
+
}
|
|
427
607
|
const top = ranked[0];
|
|
428
608
|
if (!top || top.score < START_SCORE) return null;
|
|
429
609
|
return top.hits >= START_TERMS || top.familyNamed || top.containerMatched
|