@astryxdesign/cli 0.6.4 → 0.6.5-canary.00f1ed9
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
|
@@ -1,44 +1,76 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @file discover.search leaf — free-text search across
|
|
4
|
+
* @file discover.search leaf — free-text search across installed packages and,
|
|
5
|
+
* when the project has discover sources, everything it could add.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* A free-text query always answers with a list, so its response type depends
|
|
8
|
+
* on the form of the query and never on what the project has:
|
|
9
|
+
* 1. any matches -> discover.search
|
|
10
|
+
* 2. fuzzy hits (distance <= 3) -> throw ERR_NOT_FOUND with suggestions
|
|
11
|
+
* 3. otherwise -> throw ERR_NOT_FOUND
|
|
12
|
+
* Matches are installed components, the project's other installed items,
|
|
13
|
+
* packages, and every item a source lists for a package the project could add.
|
|
14
|
+
* A caller opens one item by its package path, which ../detail answers.
|
|
12
15
|
*
|
|
13
|
-
* @position api/discover/search —
|
|
14
|
-
*
|
|
16
|
+
* @position api/discover/search — pure ranking over the installed component
|
|
17
|
+
* names and ../_catalog-view's search items.
|
|
15
18
|
*/
|
|
16
19
|
|
|
17
|
-
import {findComponent} from '../_adapter.mjs';
|
|
18
|
-
import {docFromResult} from '../detail/doc/doc.mjs';
|
|
19
20
|
import {levenshteinDistance} from '../../../foundation/text/string-utils.mjs';
|
|
20
21
|
import {AstryxError} from '../../error.mjs';
|
|
21
22
|
import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
|
|
23
|
+
import {DISCOVER_KINDS} from '../../../authoring/discover/parse.mjs';
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* @typedef {import('../_package-scanner.mjs').ScannedPackage} ScannedPackage
|
|
27
|
+
* @typedef {import('../_catalog-view.mjs').SearchItem} SearchItem
|
|
25
28
|
*/
|
|
26
29
|
|
|
30
|
+
const KIND_ORDER = ['package', ...DISCOVER_KINDS];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* How well an item matches: 0 exact name, 1 name prefix, 2 name substring,
|
|
34
|
+
* 3 title, summary, keyword, or description; null for no match.
|
|
35
|
+
* @param {SearchItem} item
|
|
36
|
+
* @param {string} lower
|
|
37
|
+
* @returns {number | null}
|
|
38
|
+
*/
|
|
39
|
+
function rank(item, lower) {
|
|
40
|
+
const name = item.name.toLowerCase();
|
|
41
|
+
if (name === lower) return 0;
|
|
42
|
+
if (name.startsWith(lower)) return 1;
|
|
43
|
+
if (name.includes(lower)) return 2;
|
|
44
|
+
const text = [
|
|
45
|
+
item.title,
|
|
46
|
+
item.summary,
|
|
47
|
+
item.description,
|
|
48
|
+
...(item.keywords ?? []),
|
|
49
|
+
]
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.join('\n')
|
|
52
|
+
.toLowerCase();
|
|
53
|
+
return text.includes(lower) ? 3 : null;
|
|
54
|
+
}
|
|
55
|
+
|
|
27
56
|
/**
|
|
28
57
|
* Search all packages for `query` (a free-text term that never starts with
|
|
29
|
-
* `@`). Resolves to a
|
|
30
|
-
*
|
|
31
|
-
* fuzzy suggestions when any exist.
|
|
58
|
+
* `@`). Resolves to a search response when anything matches, even a single
|
|
59
|
+
* item or an exact component name, or throws AstryxError (ERR_NOT_FOUND) —
|
|
60
|
+
* with fuzzy suggestions when any exist.
|
|
32
61
|
*
|
|
33
|
-
* @param {ScannedPackage[]} packages
|
|
62
|
+
* @param {ScannedPackage[]} packages installed packages
|
|
34
63
|
* @param {string} query
|
|
35
|
-
* @param {{
|
|
36
|
-
*
|
|
37
|
-
* import('
|
|
38
|
-
*
|
|
39
|
-
*
|
|
64
|
+
* @param {{
|
|
65
|
+
* items?: SearchItem[],
|
|
66
|
+
* type?: import('../../../authoring/discover/type').DiscoverKind,
|
|
67
|
+
* only?: 'installed' | 'available',
|
|
68
|
+
* limit?: number,
|
|
69
|
+
* }} opts
|
|
70
|
+
* @returns {Promise<import('../discover.type.mjs').DiscoverSearchResponse>}
|
|
40
71
|
*/
|
|
41
|
-
export async function search(packages, query,
|
|
72
|
+
export async function search(packages, query, opts) {
|
|
73
|
+
const {items = [], type, only, limit} = opts;
|
|
42
74
|
// An empty query must error, not match every component via `.includes('')`
|
|
43
75
|
// (parity with the api/search leaf). The discover() dispatcher already routes
|
|
44
76
|
// an empty query to list, but the leaf must be safe on its own.
|
|
@@ -51,50 +83,64 @@ export async function search(packages, query, {lang, zh}) {
|
|
|
51
83
|
}
|
|
52
84
|
const lower = query.toLowerCase();
|
|
53
85
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
86
|
+
/** @type {SearchItem[]} */
|
|
87
|
+
const installedComponents = packages.flatMap(pkg =>
|
|
88
|
+
pkg.components.map(name => ({
|
|
89
|
+
package: pkg.name,
|
|
90
|
+
kind: /** @type {const} */ ('component'),
|
|
91
|
+
name,
|
|
92
|
+
installed: true,
|
|
93
|
+
})),
|
|
94
|
+
);
|
|
66
95
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
96
|
+
const ranked = [...installedComponents, ...items]
|
|
97
|
+
.filter(item => (type == null ? true : item.kind === type))
|
|
98
|
+
.filter(item =>
|
|
99
|
+
only === 'installed'
|
|
100
|
+
? item.installed
|
|
101
|
+
: only === 'available'
|
|
102
|
+
? !item.installed
|
|
103
|
+
: true,
|
|
104
|
+
)
|
|
105
|
+
.map(item => ({item, score: rank(item, lower)}))
|
|
106
|
+
.filter(
|
|
107
|
+
/** @returns {m is {item: SearchItem, score: number}} */
|
|
108
|
+
m => m.score != null,
|
|
109
|
+
)
|
|
110
|
+
.sort(
|
|
111
|
+
(a, b) =>
|
|
112
|
+
a.score - b.score ||
|
|
113
|
+
Number(b.item.installed) - Number(a.item.installed) ||
|
|
114
|
+
KIND_ORDER.indexOf(a.item.kind) - KIND_ORDER.indexOf(b.item.kind) ||
|
|
115
|
+
a.item.package.localeCompare(b.item.package) ||
|
|
116
|
+
a.item.name.localeCompare(b.item.name),
|
|
117
|
+
);
|
|
72
118
|
|
|
73
|
-
if (
|
|
119
|
+
if (ranked.length > 0) {
|
|
120
|
+
const matches = ranked.map(({item}) => ({
|
|
121
|
+
package: item.package,
|
|
122
|
+
component: item.name,
|
|
123
|
+
kind: item.kind,
|
|
124
|
+
installed: item.installed,
|
|
125
|
+
...(item.title ? {title: item.title} : {}),
|
|
126
|
+
...(item.summary ? {summary: item.summary} : {}),
|
|
127
|
+
}));
|
|
128
|
+
const shown = limit == null ? matches : matches.slice(0, limit);
|
|
74
129
|
return {
|
|
75
130
|
type: 'discover.search',
|
|
76
131
|
data: {
|
|
77
132
|
query,
|
|
78
|
-
matches:
|
|
79
|
-
|
|
80
|
-
component: m.comp,
|
|
81
|
-
})),
|
|
133
|
+
matches: shown,
|
|
134
|
+
...(shown.length < matches.length ? {total: matches.length} : {}),
|
|
82
135
|
},
|
|
83
136
|
};
|
|
84
137
|
}
|
|
85
138
|
|
|
86
|
-
// Fuzzy fallback
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
allComponents.push({pkg, comp});
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
const fuzzyMatches = allComponents
|
|
95
|
-
.map(item => ({
|
|
96
|
-
...item,
|
|
97
|
-
distance: levenshteinDistance(lower, item.comp.toLowerCase()),
|
|
139
|
+
// Fuzzy fallback over installed components.
|
|
140
|
+
const fuzzyMatches = installedComponents
|
|
141
|
+
.map(entry => ({
|
|
142
|
+
...entry,
|
|
143
|
+
distance: levenshteinDistance(lower, entry.name.toLowerCase()),
|
|
98
144
|
}))
|
|
99
145
|
.filter(m => m.distance <= 3)
|
|
100
146
|
.sort((a, b) => a.distance - b.distance)
|
|
@@ -104,7 +150,7 @@ export async function search(packages, query, {lang, zh}) {
|
|
|
104
150
|
throw new AstryxError(
|
|
105
151
|
`"${query}" not found`,
|
|
106
152
|
fuzzyMatches.map(m => ({
|
|
107
|
-
name: m.
|
|
153
|
+
name: m.package + '/' + m.name,
|
|
108
154
|
reason: 'similar name',
|
|
109
155
|
})),
|
|
110
156
|
ERROR_CODES.ERR_NOT_FOUND,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @file Colocated tests for the discover.search leaf
|
|
5
|
-
*
|
|
4
|
+
* @file Colocated tests for the discover.search leaf, over a small temp docs
|
|
5
|
+
* directory shaped like a scanned package.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {describe, it, expect, beforeAll, afterAll} from 'vitest';
|
|
@@ -47,16 +47,31 @@ afterAll(() => {
|
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
describe('discover.search leaf', () => {
|
|
50
|
-
it('an exact component name
|
|
50
|
+
it('lists an exact component name first, with every other match', async () => {
|
|
51
51
|
const res = await search(packages, 'Alpha', {});
|
|
52
|
-
expect(res.type).toBe('discover.
|
|
53
|
-
expect(res.data.
|
|
52
|
+
expect(res.type).toBe('discover.search');
|
|
53
|
+
expect(res.data.matches.map(m => m.component)).toEqual([
|
|
54
|
+
'Alpha',
|
|
55
|
+
'AlphaCard',
|
|
56
|
+
]);
|
|
54
57
|
});
|
|
55
58
|
|
|
56
|
-
it('a single
|
|
59
|
+
it('lists a single match too, so the response type never depends on the data', async () => {
|
|
57
60
|
const res = await search(packages, 'card', {});
|
|
58
|
-
expect(res
|
|
59
|
-
|
|
61
|
+
expect(res).toEqual({
|
|
62
|
+
type: 'discover.search',
|
|
63
|
+
data: {
|
|
64
|
+
query: 'card',
|
|
65
|
+
matches: [
|
|
66
|
+
{
|
|
67
|
+
package: '@acme/widgets',
|
|
68
|
+
component: 'AlphaCard',
|
|
69
|
+
kind: 'component',
|
|
70
|
+
installed: true,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
});
|
|
60
75
|
});
|
|
61
76
|
|
|
62
77
|
it('multiple substring matches return a search response', async () => {
|
|
@@ -66,8 +81,18 @@ describe('discover.search leaf', () => {
|
|
|
66
81
|
data: {
|
|
67
82
|
query: 'alph',
|
|
68
83
|
matches: [
|
|
69
|
-
{
|
|
70
|
-
|
|
84
|
+
{
|
|
85
|
+
package: '@acme/widgets',
|
|
86
|
+
component: 'Alpha',
|
|
87
|
+
kind: 'component',
|
|
88
|
+
installed: true,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
package: '@acme/widgets',
|
|
92
|
+
component: 'AlphaCard',
|
|
93
|
+
kind: 'component',
|
|
94
|
+
installed: true,
|
|
95
|
+
},
|
|
71
96
|
],
|
|
72
97
|
},
|
|
73
98
|
});
|
|
@@ -116,3 +141,112 @@ describe('discover.search leaf — empty query (parity with api/search)', () =>
|
|
|
116
141
|
});
|
|
117
142
|
});
|
|
118
143
|
});
|
|
144
|
+
|
|
145
|
+
describe('discover.search leaf across every kind and source', () => {
|
|
146
|
+
/** @type {any[]} */
|
|
147
|
+
const items = [
|
|
148
|
+
{
|
|
149
|
+
package: '@acme/widgets',
|
|
150
|
+
kind: 'template',
|
|
151
|
+
name: 'pages/AlphaHome',
|
|
152
|
+
installed: true,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
package: '@acme/charts',
|
|
156
|
+
kind: 'package',
|
|
157
|
+
name: '@acme/charts',
|
|
158
|
+
installed: false,
|
|
159
|
+
description: 'Charts for alpha dashboards',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
package: '@acme/charts',
|
|
163
|
+
kind: 'component',
|
|
164
|
+
name: 'AlphaChart',
|
|
165
|
+
installed: false,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
package: '@acme/charts',
|
|
169
|
+
kind: 'doc',
|
|
170
|
+
name: 'guide',
|
|
171
|
+
installed: false,
|
|
172
|
+
summary: 'How to chart',
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
it('ranks every match by how closely its name matches, installed first among equals', async () => {
|
|
177
|
+
const res = await search(packages, 'alph', {items});
|
|
178
|
+
expect(res.type).toBe('discover.search');
|
|
179
|
+
expect(
|
|
180
|
+
res.data.matches.map(m => [m.kind, m.component, m.installed]),
|
|
181
|
+
).toEqual([
|
|
182
|
+
['component', 'Alpha', true],
|
|
183
|
+
['component', 'AlphaCard', true],
|
|
184
|
+
['component', 'AlphaChart', false],
|
|
185
|
+
['template', 'pages/AlphaHome', true],
|
|
186
|
+
['package', '@acme/charts', false],
|
|
187
|
+
]);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('lists an exact installed component name with the matches from every source', async () => {
|
|
191
|
+
const res = await search(packages, 'Alpha', {items});
|
|
192
|
+
expect(res.type).toBe('discover.search');
|
|
193
|
+
expect(res.data.matches[0]).toEqual({
|
|
194
|
+
package: '@acme/widgets',
|
|
195
|
+
component: 'Alpha',
|
|
196
|
+
kind: 'component',
|
|
197
|
+
installed: true,
|
|
198
|
+
});
|
|
199
|
+
expect(res.data.matches.map(m => m.component)).toContain('AlphaChart');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('lists a single partial component match when other items match too', async () => {
|
|
203
|
+
const res = await search(packages, 'card', {
|
|
204
|
+
items: [
|
|
205
|
+
...items,
|
|
206
|
+
{
|
|
207
|
+
package: '@acme/charts',
|
|
208
|
+
kind: 'template',
|
|
209
|
+
name: 'pages/CardGrid',
|
|
210
|
+
installed: false,
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
});
|
|
214
|
+
expect(res.type).toBe('discover.search');
|
|
215
|
+
expect(res.data.matches.map(m => m.component)).toEqual([
|
|
216
|
+
'AlphaCard',
|
|
217
|
+
'pages/CardGrid',
|
|
218
|
+
]);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('lists one installed component when nothing else matches', async () => {
|
|
222
|
+
const res = await search(packages, 'card', {items});
|
|
223
|
+
expect(res.type).toBe('discover.search');
|
|
224
|
+
expect(res.data.matches.map(m => m.component)).toEqual(['AlphaCard']);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('keeps one kind with type, and one side with only', async () => {
|
|
228
|
+
const templates = await search(packages, 'alph', {items, type: 'template'});
|
|
229
|
+
expect(templates.data.matches.map(m => m.component)).toEqual([
|
|
230
|
+
'pages/AlphaHome',
|
|
231
|
+
]);
|
|
232
|
+
const available = await search(packages, 'alph', {
|
|
233
|
+
items,
|
|
234
|
+
only: 'available',
|
|
235
|
+
});
|
|
236
|
+
expect(available.data.matches.map(m => m.component)).toEqual([
|
|
237
|
+
'AlphaChart',
|
|
238
|
+
'@acme/charts',
|
|
239
|
+
]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('caps the list at limit and reports the total', async () => {
|
|
243
|
+
const res = await search(packages, 'alph', {items, limit: 2});
|
|
244
|
+
expect(res.data.matches).toHaveLength(2);
|
|
245
|
+
expect(res.data.total).toBe(5);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('matches titles, summaries, keywords, and descriptions too', async () => {
|
|
249
|
+
const res = await search(packages, 'how to chart', {items});
|
|
250
|
+
expect(res.data.matches.map(m => m.component)).toEqual(['guide']);
|
|
251
|
+
});
|
|
252
|
+
});
|
package/api/docs/_adapter.d.mts
CHANGED
|
@@ -77,10 +77,12 @@ export function docsLinkProblems(catalog: DocsCatalog, tree: DocsTree, { owner,
|
|
|
77
77
|
/**
|
|
78
78
|
* What \`astryx doctor integration docs\` checks in one integration's docs: the
|
|
79
79
|
* docs tree they build beside the CLI's (namespaces, placements, routes) and
|
|
80
|
-
* every link in them (spec:AST-046, spec:AST-047).
|
|
80
|
+
* every link in them (spec:AST-046, spec:AST-047). A tree problem hides a doc,
|
|
81
|
+
* so it is an error; a link that names no doc prints as written, so it is a
|
|
82
|
+
* warning.
|
|
81
83
|
* @param {{name: string}} integration
|
|
82
84
|
* @param {{records: import('../../foundation/discovery/docs-discovery.mjs').DocsTopicRecord[], namespaces: import('../../foundation/doc-compiler/tree.mjs').TreeNamespaceInput[], guides: import('../../foundation/doc-compiler/tree.mjs').TreeDocInput[]}} discovered
|
|
83
|
-
* @returns {Promise<string
|
|
85
|
+
* @returns {Promise<Array<{severity: 'error' | 'warning', message: string}>>}
|
|
84
86
|
*/
|
|
85
87
|
export function packageDocsProblems(integration: {
|
|
86
88
|
name: string;
|
|
@@ -88,7 +90,10 @@ export function packageDocsProblems(integration: {
|
|
|
88
90
|
records: import("../../foundation/discovery/docs-discovery.mjs").DocsTopicRecord[];
|
|
89
91
|
namespaces: import("../../foundation/doc-compiler/tree.mjs").TreeNamespaceInput[];
|
|
90
92
|
guides: import("../../foundation/doc-compiler/tree.mjs").TreeDocInput[];
|
|
91
|
-
}): Promise<
|
|
93
|
+
}): Promise<Array<{
|
|
94
|
+
severity: "error" | "warning";
|
|
95
|
+
message: string;
|
|
96
|
+
}>>;
|
|
92
97
|
/**
|
|
93
98
|
* How a token reference finds its target: the topic it names in `catalog`,
|
|
94
99
|
* lowered for the same language.
|
package/api/docs/_adapter.mjs
CHANGED
|
@@ -667,10 +667,12 @@ export async function docsLinkProblems(
|
|
|
667
667
|
/**
|
|
668
668
|
* What \`astryx doctor integration docs\` checks in one integration's docs: the
|
|
669
669
|
* docs tree they build beside the CLI's (namespaces, placements, routes) and
|
|
670
|
-
* every link in them (spec:AST-046, spec:AST-047).
|
|
670
|
+
* every link in them (spec:AST-046, spec:AST-047). A tree problem hides a doc,
|
|
671
|
+
* so it is an error; a link that names no doc prints as written, so it is a
|
|
672
|
+
* warning.
|
|
671
673
|
* @param {{name: string}} integration
|
|
672
674
|
* @param {{records: import('../../foundation/discovery/docs-discovery.mjs').DocsTopicRecord[], namespaces: import('../../foundation/doc-compiler/tree.mjs').TreeNamespaceInput[], guides: import('../../foundation/doc-compiler/tree.mjs').TreeDocInput[]}} discovered
|
|
673
|
-
* @returns {Promise<string
|
|
675
|
+
* @returns {Promise<Array<{severity: 'error' | 'warning', message: string}>>}
|
|
674
676
|
*/
|
|
675
677
|
export async function packageDocsProblems(integration, discovered) {
|
|
676
678
|
const catalog = DocsCatalog.fromBuiltins();
|
|
@@ -680,12 +682,18 @@ export async function packageDocsProblems(integration, discovered) {
|
|
|
680
682
|
guides: discovered.guides.map(input => ({...input, rank: 1})),
|
|
681
683
|
});
|
|
682
684
|
const tree = await projectTree(catalog);
|
|
685
|
+
/** @type {Array<{severity: 'error' | 'warning', message: string}>} */
|
|
683
686
|
const problems = tree.diagnostics
|
|
684
687
|
.filter(d => d.severity === 'error' && d.provider === integration.name)
|
|
685
|
-
.map(d =>
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
688
|
+
.map(d => ({
|
|
689
|
+
severity: /** @type {const} */ ('error'),
|
|
690
|
+
message: `${d.source ?? integration.name}: ${d.message}`,
|
|
691
|
+
}));
|
|
692
|
+
for (const message of await docsLinkProblems(catalog, tree, {
|
|
693
|
+
owner: integration.name,
|
|
694
|
+
})) {
|
|
695
|
+
problems.push({severity: 'warning', message});
|
|
696
|
+
}
|
|
689
697
|
return problems;
|
|
690
698
|
}
|
|
691
699
|
|
|
@@ -76,6 +76,32 @@ describe('reference doc overlays (#2182)', () => {
|
|
|
76
76
|
).toEqual([]);
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
+
it(`${topic} --${variant}: every content override lands on a block of its own type`, async () => {
|
|
80
|
+
// Blocks are matched by index and type, and a mismatch is dropped with
|
|
81
|
+
// no warning: a prose override aimed at a code block leaves the base
|
|
82
|
+
// text in place, so the reader gets a translated title over an English
|
|
83
|
+
// body. Pad with null to reach the block you mean.
|
|
84
|
+
const base = await load(basePath);
|
|
85
|
+
const overlayMod = await load(overlayPath);
|
|
86
|
+
const overlay = overlayMod.docsDense || overlayMod.docsZh;
|
|
87
|
+
const byTitle = new Map(base.docs.sections.map(s => [s.title, s]));
|
|
88
|
+
const dropped = [];
|
|
89
|
+
for (const entry of overlay.sections || []) {
|
|
90
|
+
const section = byTitle.get(entry.section);
|
|
91
|
+
if (!section) continue;
|
|
92
|
+
(entry.content || []).forEach((block, i) => {
|
|
93
|
+
if (block == null) return;
|
|
94
|
+
const target = section.content[i];
|
|
95
|
+
if (target?.type !== block.type) {
|
|
96
|
+
dropped.push(
|
|
97
|
+
`${entry.section} block ${i}: ${block.type} over ${target?.type ?? 'nothing'}`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
expect(dropped, `${topic}.doc.${variant}.mjs overrides that never apply`).toEqual([]);
|
|
103
|
+
});
|
|
104
|
+
|
|
79
105
|
it(`${topic} --${variant}: no base section is overridden twice`, async () => {
|
|
80
106
|
const overlayMod = await load(overlayPath);
|
|
81
107
|
const overlay = overlayMod.docsDense || overlayMod.docsZh;
|
|
@@ -127,7 +153,7 @@ describe('the reported defect: docs tokens --dense (#2182)', () => {
|
|
|
127
153
|
const zh = await docs('theme', null, {zh: true});
|
|
128
154
|
const titles = zh.data.sections.map(s => s.title);
|
|
129
155
|
// Every section the overlay translates must appear once, in Chinese only.
|
|
130
|
-
expect(titles).not.toContain('
|
|
156
|
+
expect(titles).not.toContain('Dark mode');
|
|
131
157
|
expect(titles).toContain('亮/暗模式');
|
|
132
158
|
});
|
|
133
159
|
});
|
package/api/docs/docs.doc.mjs
CHANGED
|
@@ -27,7 +27,7 @@ export const doc = {
|
|
|
27
27
|
'A route opens a node of the docs tree instead: a namespace such as ' +
|
|
28
28
|
"`cli/api` returns its children one level down, a typed doc such as " +
|
|
29
29
|
"`cli/api/functions/search` returns its content, and a guide the tree " +
|
|
30
|
-
'places (`cli/integrations`) reads like any topic. ' +
|
|
30
|
+
'places (`cli/integrations/quick-start`) reads like any topic. ' +
|
|
31
31
|
'Every read but the list carries `links`, the commands that move from it: ' +
|
|
32
32
|
'`up` to the level it sits in, `previous` and `next` to its neighbors, and, ' +
|
|
33
33
|
'for a typed doc, `related` to the docs it names (its command or function, ' +
|
|
@@ -137,7 +137,7 @@ export const doc = {
|
|
|
137
137
|
{label: 'One API function', code: "await docs('cli/api/functions/search');"},
|
|
138
138
|
{
|
|
139
139
|
label: 'A whole guide from the docs tree',
|
|
140
|
-
code: "await docs('cli/integrations');",
|
|
140
|
+
code: "await docs('cli/integrations/quick-start');",
|
|
141
141
|
},
|
|
142
142
|
{label: 'One section by key', code: "await docs('tokens', 'spacing');"},
|
|
143
143
|
],
|
package/api/docs/docs.test.mjs
CHANGED
|
@@ -14,6 +14,20 @@ import {AstryxError} from '../error.mjs';
|
|
|
14
14
|
|
|
15
15
|
const SLOW = 30_000;
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* The first guide a namespace places, read from the tree rather than named,
|
|
19
|
+
* so a restructure of the guides does not break the reads under test.
|
|
20
|
+
* @param {any} node the data of a docs.node read
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
function placedGuide(node) {
|
|
24
|
+
const guide = node.slots
|
|
25
|
+
.flatMap((/** @type {any} */ slot) => slot.children)
|
|
26
|
+
.find((/** @type {any} */ child) => child.kind === 'generic');
|
|
27
|
+
if (guide == null) throw new Error(`${node.route} places no guide`);
|
|
28
|
+
return guide.route;
|
|
29
|
+
}
|
|
30
|
+
|
|
17
31
|
describe('docs() dispatcher routing', () => {
|
|
18
32
|
it('no topic -> docs.list', async () => {
|
|
19
33
|
const r = await docs();
|
|
@@ -37,6 +51,15 @@ describe('docs() dispatcher routing', () => {
|
|
|
37
51
|
expect(r.type).toBe('docs.index');
|
|
38
52
|
}, SLOW);
|
|
39
53
|
|
|
54
|
+
it('reads a shortened section by its old key, which its title still derives', async () => {
|
|
55
|
+
const r = await docs(
|
|
56
|
+
'styling',
|
|
57
|
+
'stylex-build-setup-required-for-swizzled-components',
|
|
58
|
+
);
|
|
59
|
+
expect(r.type).toBe('docs.detail.section');
|
|
60
|
+
expect(r.data).toMatchObject({id: 'stylex-setup'});
|
|
61
|
+
}, SLOW);
|
|
62
|
+
|
|
40
63
|
it('topic + section -> docs.detail.section', async () => {
|
|
41
64
|
const {data} = await docs();
|
|
42
65
|
let routed = null;
|
|
@@ -126,11 +149,15 @@ describe('docs() dispatcher routing', () => {
|
|
|
126
149
|
}, SLOW);
|
|
127
150
|
|
|
128
151
|
it('a guide the tree places reads like a topic: the whole doc, its index, a section', async () => {
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
expect(
|
|
152
|
+
// cli/integrations is a namespace of short guides; each guide reads like a topic.
|
|
153
|
+
const integrations = await docs('cli/integrations');
|
|
154
|
+
expect(integrations.type).toBe('docs.node');
|
|
155
|
+
const guide = placedGuide(integrations.data);
|
|
156
|
+
expect((await docs(guide)).type).toBe('docs.detail');
|
|
157
|
+
const index = await docs(guide, undefined, {index: true});
|
|
158
|
+
expect(index).toMatchObject({type: 'docs.index', data: {name: guide}});
|
|
132
159
|
expect(index.data.sections.length).toBeGreaterThan(1);
|
|
133
|
-
expect((await docs(
|
|
160
|
+
expect((await docs(guide, index.data.sections[0].id)).type).toBe(
|
|
134
161
|
'docs.detail.section',
|
|
135
162
|
);
|
|
136
163
|
}, SLOW);
|
|
@@ -142,22 +169,31 @@ describe('docs() dispatcher routing', () => {
|
|
|
142
169
|
expect(leaf.links.up).toBe('astryx docs cli/api/functions');
|
|
143
170
|
expect(leaf.links.previous).toMatch(/^astryx docs cli\/api\/functions\/[a-z-]+$/);
|
|
144
171
|
expect(leaf.links.next).toMatch(/^astryx docs cli\/api\/functions\/[a-z-]+$/);
|
|
145
|
-
const
|
|
172
|
+
const integrations = (await docs('cli/integrations')).data;
|
|
173
|
+
const guide = placedGuide(integrations);
|
|
174
|
+
const siblings = integrations.slots
|
|
175
|
+
.find(slot => slot.children.some(child => child.route === guide))
|
|
176
|
+
.children.map(child => child.route);
|
|
177
|
+
const at = siblings.indexOf(guide);
|
|
178
|
+
const index = await docs(guide, undefined, {index: true});
|
|
146
179
|
// A guide moves across its namespace's slot, as any tree node does.
|
|
147
180
|
expect(index.data.links).toEqual({
|
|
148
|
-
up: 'astryx docs cli',
|
|
149
|
-
|
|
181
|
+
up: 'astryx docs cli/integrations',
|
|
182
|
+
...(at > 0 ? {previous: `astryx docs ${siblings[at - 1]}`} : {}),
|
|
183
|
+
...(at < siblings.length - 1
|
|
184
|
+
? {next: `astryx docs ${siblings[at + 1]}`}
|
|
185
|
+
: {}),
|
|
150
186
|
});
|
|
151
|
-
const first = (await docs(
|
|
187
|
+
const first = (await docs(guide, index.data.sections[0].id)).data;
|
|
152
188
|
expect(first.links).toEqual({
|
|
153
|
-
up:
|
|
154
|
-
next: `astryx docs
|
|
189
|
+
up: `astryx docs ${guide} --index`,
|
|
190
|
+
next: `astryx docs ${guide} ${index.data.sections[1].id}`,
|
|
155
191
|
});
|
|
156
192
|
const last = index.data.sections.at(-1).id;
|
|
157
|
-
const end = (await docs(
|
|
193
|
+
const end = (await docs(guide, last)).data;
|
|
158
194
|
expect(end.links.next).toBeUndefined();
|
|
159
195
|
expect(end.links.previous).toBe(
|
|
160
|
-
`astryx docs
|
|
196
|
+
`astryx docs ${guide} ${index.data.sections.at(-2).id}`,
|
|
161
197
|
);
|
|
162
198
|
// A flat topic's home is the Unorganized level, and it moves across it.
|
|
163
199
|
const flat = (await docs('principles')).data.links;
|
|
@@ -208,12 +244,12 @@ describe('docs() dispatcher routing', () => {
|
|
|
208
244
|
const err = await docs('cli', 'commands').catch(e => e);
|
|
209
245
|
expect(err).toBeInstanceOf(AstryxError);
|
|
210
246
|
expect(err.code).toBe('ERR_UNKNOWN_SECTION');
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
247
|
+
// It names the namespace's children, in the order its slots list them.
|
|
248
|
+
const cli = (await docs('cli')).data;
|
|
249
|
+
expect(err.suggestions.map(s => s.name)).toEqual(
|
|
250
|
+
cli.slots.flatMap(slot => slot.children.map(child => child.route)),
|
|
251
|
+
);
|
|
252
|
+
expect(err.suggestions.map(s => s.name)).toContain('cli/commands');
|
|
217
253
|
}, SLOW);
|
|
218
254
|
|
|
219
255
|
it('an unknown route suggests the children of the deepest namespace it reaches', async () => {
|
|
@@ -477,6 +477,23 @@ describe('integration docs in the docs tree', () => {
|
|
|
477
477
|
);
|
|
478
478
|
}, SLOW);
|
|
479
479
|
|
|
480
|
+
it('fails doctor integration docs on a placement that hides a guide, and only warns on a link', async () => {
|
|
481
|
+
scaffold({
|
|
482
|
+
...kit(),
|
|
483
|
+
'lost.doc.mjs': guide('lost', {
|
|
484
|
+
placement: {parent: 'namespace:nope', slot: 'guides'},
|
|
485
|
+
}),
|
|
486
|
+
});
|
|
487
|
+
const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
|
|
488
|
+
expect(result.data.issues).toContainEqual(
|
|
489
|
+
expect.objectContaining({
|
|
490
|
+
code: 'invalid_doc_graph',
|
|
491
|
+
severity: 'error',
|
|
492
|
+
message: expect.stringContaining('namespace:nope'),
|
|
493
|
+
}),
|
|
494
|
+
);
|
|
495
|
+
}, SLOW);
|
|
496
|
+
|
|
480
497
|
it("resolves an extension's links against the extension's provider, not the base topic's", async () => {
|
|
481
498
|
scaffold({
|
|
482
499
|
...kit(),
|