@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
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file `astryx discover` with a discover source: the list, a package page, a
|
|
5
|
+
* search, and the refused option pair, driven through the real CLI against a
|
|
6
|
+
* hermetic project whose astryx.config sets `discover`. Saved copies go to a
|
|
7
|
+
* temp cache directory, never the project.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
11
|
+
import * as fs from 'node:fs';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import * as os from 'node:os';
|
|
14
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
15
|
+
|
|
16
|
+
const CONFIG = `
|
|
17
|
+
const packages = [
|
|
18
|
+
{
|
|
19
|
+
package: '@test/kit',
|
|
20
|
+
integration: 'test-kit',
|
|
21
|
+
aliases: [],
|
|
22
|
+
latest: '3.2.0',
|
|
23
|
+
versions: [
|
|
24
|
+
{version: '3.2.0', publishedAt: '2026-09-29T00:00:00.000Z', prerelease: false, status: 'ok'},
|
|
25
|
+
{version: '3.1.4', publishedAt: '2026-09-01T00:00:00.000Z', prerelease: false, status: 'ok'},
|
|
26
|
+
],
|
|
27
|
+
contributions: [{kind: 'component', name: 'Dial'}],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
package: '@test/charts',
|
|
31
|
+
integration: 'test-charts',
|
|
32
|
+
aliases: [],
|
|
33
|
+
latest: '2.0.0',
|
|
34
|
+
versions: [
|
|
35
|
+
{version: '2.1.0-beta.1', publishedAt: '2026-09-25T00:00:00.000Z', prerelease: true, status: 'ok'},
|
|
36
|
+
{version: '2.0.0', publishedAt: '2026-09-20T00:00:00.000Z', prerelease: false, status: 'ok'},
|
|
37
|
+
],
|
|
38
|
+
contributions: [
|
|
39
|
+
{kind: 'component', name: 'Chart'},
|
|
40
|
+
{kind: 'template', name: 'pages/Report'},
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
package: '@test/boards',
|
|
45
|
+
integration: 'test-boards',
|
|
46
|
+
aliases: [],
|
|
47
|
+
latest: '1.0.0',
|
|
48
|
+
versions: [
|
|
49
|
+
{version: '1.0.0', publishedAt: '2026-09-10T00:00:00.000Z', prerelease: false, status: 'ok'},
|
|
50
|
+
],
|
|
51
|
+
contributions: [{kind: 'template', name: 'pages/DialBoard'}],
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
export default {
|
|
56
|
+
integrations: ['@test/kit'],
|
|
57
|
+
async discover({package: name}) {
|
|
58
|
+
return {
|
|
59
|
+
schemaVersion: 1,
|
|
60
|
+
source: {name: 'Test catalog', generatedAt: '2026-09-30T00:00:00.000Z', complete: true},
|
|
61
|
+
packages: packages.filter(p => name == null || p.package === name),
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
let tmpDir;
|
|
68
|
+
let project;
|
|
69
|
+
/** @type {Record<string, string | undefined>} */
|
|
70
|
+
let savedEnv;
|
|
71
|
+
|
|
72
|
+
beforeEach(() => {
|
|
73
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-discover-sources-'));
|
|
74
|
+
project = path.join(tmpDir, 'project');
|
|
75
|
+
const pkgDir = path.join(project, 'node_modules', '@test', 'kit');
|
|
76
|
+
fs.mkdirSync(path.join(pkgDir, 'components'), {recursive: true});
|
|
77
|
+
fs.writeFileSync(
|
|
78
|
+
path.join(project, 'package.json'),
|
|
79
|
+
JSON.stringify({
|
|
80
|
+
name: 'proj',
|
|
81
|
+
version: '1.0.0',
|
|
82
|
+
dependencies: {'@test/kit': '3.1.4'},
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
fs.writeFileSync(path.join(project, 'astryx.config.mjs'), CONFIG);
|
|
86
|
+
fs.writeFileSync(
|
|
87
|
+
path.join(pkgDir, 'package.json'),
|
|
88
|
+
JSON.stringify({name: '@test/kit', version: '3.1.4'}),
|
|
89
|
+
);
|
|
90
|
+
fs.writeFileSync(
|
|
91
|
+
path.join(pkgDir, 'astryx.integration.mjs'),
|
|
92
|
+
`export default {components: './components'};\n`,
|
|
93
|
+
);
|
|
94
|
+
fs.writeFileSync(
|
|
95
|
+
path.join(pkgDir, 'components', 'Dial.doc.mjs'),
|
|
96
|
+
`export const docs = {name: 'Dial', usage: {description: 'A dial.'}};\n`,
|
|
97
|
+
);
|
|
98
|
+
fs.writeFileSync(
|
|
99
|
+
path.join(pkgDir, 'components', 'Dial.tsx'),
|
|
100
|
+
`export function Dial() { return null; }\n`,
|
|
101
|
+
);
|
|
102
|
+
// The saved copy lives in the per-user cache; point it at the temp dir.
|
|
103
|
+
savedEnv = {
|
|
104
|
+
HOME: process.env.HOME,
|
|
105
|
+
XDG_CACHE_HOME: process.env.XDG_CACHE_HOME,
|
|
106
|
+
LOCALAPPDATA: process.env.LOCALAPPDATA,
|
|
107
|
+
};
|
|
108
|
+
process.env.HOME = path.join(tmpDir, 'home');
|
|
109
|
+
process.env.XDG_CACHE_HOME = path.join(tmpDir, 'cache');
|
|
110
|
+
process.env.LOCALAPPDATA = path.join(tmpDir, 'localappdata');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
afterEach(() => {
|
|
114
|
+
for (const [key, value] of Object.entries(savedEnv)) {
|
|
115
|
+
if (value === undefined) delete process.env[key];
|
|
116
|
+
else process.env[key] = value;
|
|
117
|
+
}
|
|
118
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
/** The per-user cache directory this platform uses under the redirected env. */
|
|
122
|
+
function userCacheDir() {
|
|
123
|
+
if (process.platform === 'win32') {
|
|
124
|
+
return path.join(tmpDir, 'localappdata', 'astryx', 'Cache');
|
|
125
|
+
}
|
|
126
|
+
if (process.platform === 'darwin') {
|
|
127
|
+
return path.join(tmpDir, 'home', 'Library', 'Caches', 'astryx');
|
|
128
|
+
}
|
|
129
|
+
return path.join(tmpDir, 'cache', 'astryx');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
describe('astryx discover with a discover source', () => {
|
|
133
|
+
it('lists what the project has and what it could add, in --json', async () => {
|
|
134
|
+
const {status, stdout} = await runCli(['discover', '--json'], {
|
|
135
|
+
cwd: project,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
expect(status).toBe(0);
|
|
139
|
+
const {data, meta} = JSON.parse(stdout);
|
|
140
|
+
expect(data).toEqual([
|
|
141
|
+
expect.objectContaining({
|
|
142
|
+
name: '@test/kit',
|
|
143
|
+
components: ['Dial'],
|
|
144
|
+
version: '3.1.4',
|
|
145
|
+
latest: '3.2.0',
|
|
146
|
+
}),
|
|
147
|
+
]);
|
|
148
|
+
expect(meta.available).toEqual([
|
|
149
|
+
{
|
|
150
|
+
name: '@test/charts',
|
|
151
|
+
components: ['Chart'],
|
|
152
|
+
version: '2.0.0',
|
|
153
|
+
templates: ['pages/Report'],
|
|
154
|
+
source: 'Test catalog',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: '@test/boards',
|
|
158
|
+
components: [],
|
|
159
|
+
version: '1.0.0',
|
|
160
|
+
templates: ['pages/DialBoard'],
|
|
161
|
+
source: 'Test catalog',
|
|
162
|
+
},
|
|
163
|
+
]);
|
|
164
|
+
expect(meta.sources).toEqual([
|
|
165
|
+
expect.objectContaining({
|
|
166
|
+
name: 'Test catalog',
|
|
167
|
+
from: 'astryx.config',
|
|
168
|
+
status: 'fresh',
|
|
169
|
+
}),
|
|
170
|
+
]);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('prints both sides as records', async () => {
|
|
174
|
+
const {status, stdout} = await runCli(['discover'], {cwd: project});
|
|
175
|
+
|
|
176
|
+
expect(status).toBe(0);
|
|
177
|
+
expect(stdout).toMatch(/^Installed$/m);
|
|
178
|
+
expect(stdout).toMatch(/^Available$/m);
|
|
179
|
+
expect(stdout).toMatch(/^name:\s+@test\/charts$/m);
|
|
180
|
+
expect(stdout).toMatch(/^latest:\s+3\.2\.0$/m);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('shows a package it does not have with its releases and the command that adds it, and never runs it', async () => {
|
|
184
|
+
const {status, stdout} = await runCli(['discover', '@test/charts'], {
|
|
185
|
+
cwd: project,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
expect(status).toBe(0);
|
|
189
|
+
expect(stdout).toMatch(/^installed:\s+false$/m);
|
|
190
|
+
expect(stdout).toContain('- 2.0.0 2026-09-20 latest');
|
|
191
|
+
expect(stdout).not.toContain('2.1.0-beta.1 ');
|
|
192
|
+
expect(stdout).toContain('1 prerelease is not listed.');
|
|
193
|
+
// The verb follows the detected package manager.
|
|
194
|
+
expect(stdout).toMatch(
|
|
195
|
+
/^(npm install|pnpm add|yarn add|bun add) @test\/charts$/m,
|
|
196
|
+
);
|
|
197
|
+
expect(
|
|
198
|
+
fs.existsSync(path.join(project, 'node_modules', '@test', 'charts')),
|
|
199
|
+
).toBe(false);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('says which item is missing from a package only a source lists', async () => {
|
|
203
|
+
const {status, stdout} = await runCli(
|
|
204
|
+
['discover', '@test/charts/Nope', '--json'],
|
|
205
|
+
{cwd: project},
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
expect(status).toBe(1);
|
|
209
|
+
const {code, error} = JSON.parse(stdout);
|
|
210
|
+
expect(code).toBe('ERR_UNKNOWN_COMPONENT');
|
|
211
|
+
expect(error).toBe('"Nope" not found in @test/charts');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('searches every kind in every source', async () => {
|
|
215
|
+
const {status, stdout} = await runCli(['discover', 'report', '--json'], {
|
|
216
|
+
cwd: project,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
expect(status).toBe(0);
|
|
220
|
+
expect(JSON.parse(stdout).data.matches).toEqual([
|
|
221
|
+
{
|
|
222
|
+
package: '@test/charts',
|
|
223
|
+
component: 'pages/Report',
|
|
224
|
+
kind: 'template',
|
|
225
|
+
installed: false,
|
|
226
|
+
},
|
|
227
|
+
]);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('refuses --installed with --available', async () => {
|
|
231
|
+
const {status, stdout} = await runCli(
|
|
232
|
+
['discover', '--installed', '--available', '--json'],
|
|
233
|
+
{cwd: project},
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
expect(status).toBe(1);
|
|
237
|
+
expect(JSON.parse(stdout).code).toBe('ERR_INVALID_OPTION');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('lists every match for a free-text query, even an exact component name, and opens one by its package path', async () => {
|
|
241
|
+
const exact = await runCli(['discover', 'Dial', '--json'], {cwd: project});
|
|
242
|
+
const {type, data} = JSON.parse(exact.stdout);
|
|
243
|
+
expect(type).toBe('discover.search');
|
|
244
|
+
expect(data.matches.map(m => [m.component, m.installed])).toEqual([
|
|
245
|
+
['Dial', true],
|
|
246
|
+
['pages/DialBoard', false],
|
|
247
|
+
]);
|
|
248
|
+
|
|
249
|
+
const opened = await runCli(['discover', '@test/kit/Dial', '--json'], {
|
|
250
|
+
cwd: project,
|
|
251
|
+
});
|
|
252
|
+
expect(JSON.parse(opened.stdout).type).toBe('discover.detail.doc');
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('saves the answer in the user cache and writes nothing into the project', async () => {
|
|
256
|
+
const before = fs.readdirSync(project).sort();
|
|
257
|
+
await runCli(['discover', '--json'], {cwd: project});
|
|
258
|
+
|
|
259
|
+
expect(fs.readdirSync(project).sort()).toEqual(before);
|
|
260
|
+
expect(fs.existsSync(path.join(project, 'node_modules', '.cache'))).toBe(
|
|
261
|
+
false,
|
|
262
|
+
);
|
|
263
|
+
expect(fs.readdirSync(path.join(userCacheDir(), 'discover'))).toHaveLength(
|
|
264
|
+
1,
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
@@ -47,7 +47,7 @@ export const doc = {
|
|
|
47
47
|
{label: 'One section', cli: 'astryx docs theme quick-start'},
|
|
48
48
|
{label: 'The CLI docs tree', cli: 'astryx docs cli'},
|
|
49
49
|
{label: 'One API function', cli: 'astryx docs cli/api/functions/search'},
|
|
50
|
-
{label: 'A whole guide', cli: 'astryx docs cli/integrations --full'},
|
|
50
|
+
{label: 'A whole guide', cli: 'astryx docs cli/integrations/quick-start --full'},
|
|
51
51
|
],
|
|
52
52
|
exitCodes: [
|
|
53
53
|
{code: 0, when: 'success'},
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* open one section by its key, and `--full` prints the whole topic. `--json`
|
|
8
8
|
* keeps the docs() contract: a topic returns its whole doc, and `--index` its
|
|
9
9
|
* sections.
|
|
10
|
-
* Supports --detail (full|compact|brief) and --lang (en|zh|dense).
|
|
10
|
+
* Supports --detail (full|compact|brief) and --lang (en|zh|dense). A code
|
|
11
|
+
* block's label prints above its fence, and table cells escape their pipes.
|
|
11
12
|
*
|
|
12
13
|
* Usage:
|
|
13
14
|
* astryx docs List available topics
|
|
@@ -42,21 +43,35 @@ import {doc as docsFn} from '../../../api/docs/docs.doc.mjs';
|
|
|
42
43
|
|
|
43
44
|
// ─── Formatting ──────────────────────────────────────────────────────────────
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* A table cell with its pipes escaped. Columns are separated by ` | `, and a
|
|
48
|
+
* union type such as `'light' | 'dark'` is spelled with the same character,
|
|
49
|
+
* so an unescaped cell reads as extra columns. `astryx component` escapes its
|
|
50
|
+
* prop tables the same way.
|
|
51
|
+
* @param {string | undefined} cell
|
|
52
|
+
* @returns {string}
|
|
53
|
+
*/
|
|
54
|
+
function tableCell(cell) {
|
|
55
|
+
return (cell || '').replaceAll('|', '\\|');
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
/**
|
|
46
59
|
* @param {string[]} headers
|
|
47
60
|
* @param {string[][]} rows
|
|
48
61
|
* @returns {string}
|
|
49
62
|
*/
|
|
50
63
|
function formatTable(headers, rows) {
|
|
51
|
-
const
|
|
52
|
-
|
|
64
|
+
const head = headers.map(tableCell);
|
|
65
|
+
const cells = rows.map(r => r.map(tableCell));
|
|
66
|
+
const widths = head.map((h, i) =>
|
|
67
|
+
Math.max(h.length, ...cells.map(r => (r[i] || '').length)),
|
|
53
68
|
);
|
|
54
69
|
const sep = widths.map(w => '-'.repeat(w)).join(' | ');
|
|
55
|
-
const
|
|
56
|
-
const body =
|
|
57
|
-
.map(r => r.map((c, i) =>
|
|
70
|
+
const top = head.map((h, i) => h.padEnd(widths[i])).join(' | ');
|
|
71
|
+
const body = cells
|
|
72
|
+
.map(r => r.map((c, i) => c.padEnd(widths[i])).join(' | '))
|
|
58
73
|
.join('\n');
|
|
59
|
-
return `${
|
|
74
|
+
return `${top}\n${sep}\n${body}`;
|
|
60
75
|
}
|
|
61
76
|
|
|
62
77
|
/**
|
|
@@ -65,15 +80,19 @@ function formatTable(headers, rows) {
|
|
|
65
80
|
* @returns {string}
|
|
66
81
|
*/
|
|
67
82
|
function formatTableCompact(headers, rows) {
|
|
68
|
-
|
|
83
|
+
// An empty cell, such as a Default with none, adds nothing to the line.
|
|
84
|
+
return rows
|
|
85
|
+
.map(r => r.filter(cell => String(cell ?? '').trim() !== '').join(' = '))
|
|
86
|
+
.join('\n');
|
|
69
87
|
}
|
|
70
88
|
|
|
71
89
|
/**
|
|
90
|
+
* One content block as text. Exported for its tests.
|
|
72
91
|
* @param {import('@astryxdesign/cli/authoring').ReferenceContentBlock} block
|
|
73
92
|
* @param {'full' | 'compact' | 'brief'} detail
|
|
74
93
|
* @returns {string | null}
|
|
75
94
|
*/
|
|
76
|
-
function formatBlock(block, detail) {
|
|
95
|
+
export function formatBlock(block, detail) {
|
|
77
96
|
switch (block.type) {
|
|
78
97
|
case 'prose':
|
|
79
98
|
return block.text;
|
|
@@ -84,13 +103,20 @@ function formatBlock(block, detail) {
|
|
|
84
103
|
case 'code':
|
|
85
104
|
if (detail === 'compact' || detail === 'brief') return null;
|
|
86
105
|
{
|
|
87
|
-
|
|
88
|
-
|
|
106
|
+
// The label names the block, so it prints above the fence, not
|
|
107
|
+
// inside it: `// label` is not a comment in bash, CSS, JSON, or
|
|
108
|
+
// HTML, and a reader who copies the block would copy it too.
|
|
109
|
+
const label = block.label
|
|
110
|
+
? `${block.label.replace(/:\s*$/, '')}:\n`
|
|
111
|
+
: '';
|
|
112
|
+
return `${label}\`\`\`${block.lang}\n${block.code}\n\`\`\``;
|
|
89
113
|
}
|
|
90
114
|
|
|
91
115
|
case 'table':
|
|
92
116
|
if (detail === 'brief') {
|
|
93
|
-
return block.rows
|
|
117
|
+
return block.rows
|
|
118
|
+
.map(r => r.slice(0, 2).map(tableCell).join('='))
|
|
119
|
+
.join(' | ');
|
|
94
120
|
}
|
|
95
121
|
if (detail === 'compact') {
|
|
96
122
|
return formatTableCompact(block.headers, block.rows);
|
|
@@ -202,16 +228,23 @@ function emitIndex(index, run) {
|
|
|
202
228
|
}
|
|
203
229
|
|
|
204
230
|
/**
|
|
205
|
-
* One child row of a namespace
|
|
206
|
-
*
|
|
231
|
+
* One child row of a namespace. Namespace and guide route names are already
|
|
232
|
+
* readable, so repeating their titles adds noise (`start-a-template Start a
|
|
233
|
+
* template`). Typed docs keep a distinct title when it carries the real symbol
|
|
234
|
+
* name (`assert-response assertResponse()`).
|
|
207
235
|
* @param {import('../../../api/docs/docs.type.mjs').DocsNodeChild} child
|
|
208
236
|
* @returns {{name: string, summary: string}}
|
|
209
237
|
*/
|
|
210
238
|
function childRow(child) {
|
|
239
|
+
const titleAddsIdentity =
|
|
240
|
+
child.kind !== 'namespace' &&
|
|
241
|
+
child.kind !== 'generic' &&
|
|
242
|
+
child.title !== child.name;
|
|
211
243
|
return {
|
|
212
244
|
name: child.name,
|
|
213
|
-
summary:
|
|
214
|
-
|
|
245
|
+
summary: titleAddsIdentity
|
|
246
|
+
? `${child.title}: ${child.summary}`
|
|
247
|
+
: child.summary,
|
|
215
248
|
};
|
|
216
249
|
}
|
|
217
250
|
|
|
@@ -227,6 +260,17 @@ function emitNode(node, detail, run) {
|
|
|
227
260
|
if (node.kind === 'namespace') {
|
|
228
261
|
emit(
|
|
229
262
|
section(node.title, wrapText(node.summary)),
|
|
263
|
+
// A namespace may author intro `blocks`; they render above its children.
|
|
264
|
+
...(node.content?.length
|
|
265
|
+
? [
|
|
266
|
+
text(
|
|
267
|
+
node.content
|
|
268
|
+
.map(b => formatBlock(b, detail))
|
|
269
|
+
.filter(Boolean)
|
|
270
|
+
.join('\n\n'),
|
|
271
|
+
),
|
|
272
|
+
]
|
|
273
|
+
: []),
|
|
230
274
|
...node.slots.flatMap(slot => [
|
|
231
275
|
// A namespace with one slot titled like itself needs no second heading.
|
|
232
276
|
...(node.slots.length === 1 && slot.title === node.title
|
|
@@ -235,7 +279,6 @@ function emitNode(node, detail, run) {
|
|
|
235
279
|
records(slot.children.map(childRow), {
|
|
236
280
|
fields: ['name', 'summary'],
|
|
237
281
|
layout: 'inline',
|
|
238
|
-
overflow: 'truncate',
|
|
239
282
|
}),
|
|
240
283
|
]),
|
|
241
284
|
text(
|
|
@@ -5,7 +5,7 @@ import * as fs from 'node:fs';
|
|
|
5
5
|
import * as path from 'node:path';
|
|
6
6
|
import * as os from 'node:os';
|
|
7
7
|
import {Command} from 'commander';
|
|
8
|
-
import {registerDocs} from './docs.mjs';
|
|
8
|
+
import {formatBlock, registerDocs} from './docs.mjs';
|
|
9
9
|
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
10
10
|
import {displayWidth} from '../formatters/index.mjs';
|
|
11
11
|
|
|
@@ -119,7 +119,7 @@ describe('progressive reads', () => {
|
|
|
119
119
|
it("prints a topic's section index with the keys to read by", async () => {
|
|
120
120
|
const {status, stdout} = await runCli(['docs', 'theme', '--index']);
|
|
121
121
|
expect(status).toBe(0);
|
|
122
|
-
expect(stdout).toMatch(/^quick-start +
|
|
122
|
+
expect(stdout).toMatch(/^quick-start +Wrap your app in a theme/m);
|
|
123
123
|
expect(stdout).toContain('docs theme <section>');
|
|
124
124
|
expect(stdout).toMatch(/Read everything: +\S.* docs theme --full$/m);
|
|
125
125
|
expect(widest(stdout)).toBeLessThanOrEqual(120);
|
|
@@ -128,7 +128,7 @@ describe('progressive reads', () => {
|
|
|
128
128
|
it('prints one section by its key', async () => {
|
|
129
129
|
const {status, stdout} = await runCli(['docs', 'theme', 'quick-start']);
|
|
130
130
|
expect(status).toBe(0);
|
|
131
|
-
expect(stdout).toMatch(/^##
|
|
131
|
+
expect(stdout).toMatch(/^## Wrap your app in a theme/m);
|
|
132
132
|
}, SLOW);
|
|
133
133
|
|
|
134
134
|
it("lists a topic's sections by default; --full prints the whole topic", async () => {
|
|
@@ -136,7 +136,7 @@ describe('progressive reads', () => {
|
|
|
136
136
|
expect((await runCli(['docs', 'theme'])).stdout).toBe(index.stdout);
|
|
137
137
|
const full = await runCli(['docs', 'theme', '--full']);
|
|
138
138
|
expect(full.status).toBe(0);
|
|
139
|
-
expect(full.stdout).toMatch(/^##
|
|
139
|
+
expect(full.stdout).toMatch(/^## Wrap your app in a theme/m);
|
|
140
140
|
expect(full.stdout.length).toBeGreaterThan(index.stdout.length * 3);
|
|
141
141
|
expect((await runCli(['--detail', 'full', 'docs', 'theme', '--full'])).stdout).toBe(
|
|
142
142
|
full.stdout,
|
|
@@ -157,6 +157,52 @@ describe('progressive reads', () => {
|
|
|
157
157
|
}, SLOW);
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
+
describe('blocks as text', () => {
|
|
161
|
+
const SLOW = 60_000;
|
|
162
|
+
|
|
163
|
+
it('prints a code label above the fence, never inside it', () => {
|
|
164
|
+
for (const lang of ['bash', 'css', 'json', 'html', 'text', 'tsx']) {
|
|
165
|
+
expect(
|
|
166
|
+
formatBlock({type: 'code', lang, label: 'Terminal', code: 'x'}, 'full'),
|
|
167
|
+
).toBe(`Terminal:\n\`\`\`${lang}\nx\n\`\`\``);
|
|
168
|
+
}
|
|
169
|
+
expect(formatBlock({type: 'code', lang: 'bash', code: 'x'}, 'full')).toBe(
|
|
170
|
+
'```bash\nx\n```',
|
|
171
|
+
);
|
|
172
|
+
// A label that already ends in a colon does not get a second one.
|
|
173
|
+
expect(
|
|
174
|
+
formatBlock({type: 'code', lang: 'css', label: 'globals.css:', code: 'x'}, 'full'),
|
|
175
|
+
).toBe('globals.css:\n```css\nx\n```');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('escapes pipes in table cells, so a union type stays one column', () => {
|
|
179
|
+
const table = {
|
|
180
|
+
type: /** @type {const} */ ('table'),
|
|
181
|
+
headers: ['Prop', 'Type', 'Default'],
|
|
182
|
+
rows: [
|
|
183
|
+
['mode', "'system' | 'light' | 'dark'", "'system'"],
|
|
184
|
+
['theme', 'DefinedTheme', '-'],
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
const lines = /** @type {string} */ (formatBlock(table, 'full')).split('\n');
|
|
188
|
+
expect(lines).toHaveLength(4);
|
|
189
|
+
// Every line has exactly two column separators, all at the same place.
|
|
190
|
+
for (const line of lines) expect(line.split(' | ')).toHaveLength(3);
|
|
191
|
+
expect(new Set(lines.map(line => line.indexOf(' | '))).size).toBe(1);
|
|
192
|
+
expect(lines[2]).toContain("'system' \\| 'light' \\| 'dark'");
|
|
193
|
+
expect(formatBlock(table, 'brief')).toBe(
|
|
194
|
+
"mode='system' \\| 'light' \\| 'dark' | theme=DefinedTheme",
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('prints the labels of a real section above their fences', async () => {
|
|
199
|
+
const {status, stdout} = await runCli(['docs', 'theme', 'quick-start']);
|
|
200
|
+
expect(status).toBe(0);
|
|
201
|
+
expect(stdout).toContain('Install a theme package:\n```bash\nnpm install');
|
|
202
|
+
expect(stdout).not.toContain('// Install a theme package');
|
|
203
|
+
}, SLOW);
|
|
204
|
+
});
|
|
205
|
+
|
|
160
206
|
describe('the docs tree, one level at a time', () => {
|
|
161
207
|
const SLOW = 60_000;
|
|
162
208
|
/** @param {string} out */
|
|
@@ -179,12 +225,24 @@ describe('the docs tree, one level at a time', () => {
|
|
|
179
225
|
expect(stdout).toMatch(/^search +search\(\): Unified ranked search/m);
|
|
180
226
|
}, SLOW);
|
|
181
227
|
|
|
228
|
+
it('wraps namespace summaries without discarding searchable words', async () => {
|
|
229
|
+
const {status, stdout} = await runCli([
|
|
230
|
+
'docs',
|
|
231
|
+
'cli/integrations/building-blocks/templates',
|
|
232
|
+
]);
|
|
233
|
+
expect(status).toBe(0);
|
|
234
|
+
expect(stdout).toMatch(/^start-a-template +Help others build apps faster/m);
|
|
235
|
+
expect(stdout).not.toMatch(/^start-a-template +Start a template:/m);
|
|
236
|
+
expect(stdout).toMatch(/full page or page\s+section\./);
|
|
237
|
+
expect(widest(stdout)).toBeLessThanOrEqual(120);
|
|
238
|
+
}, SLOW);
|
|
239
|
+
|
|
182
240
|
it('prints a namespace: each slot, its children, and how to go down and up', async () => {
|
|
183
241
|
const {status, stdout} = await runCli(['docs', 'cli/api']);
|
|
184
242
|
expect(status).toBe(0);
|
|
185
243
|
expect(stdout).toMatch(/^API$/m);
|
|
186
244
|
expect(stdout).toMatch(/^Reference$/m);
|
|
187
|
-
expect(stdout).toMatch(/^functions +
|
|
245
|
+
expect(stdout).toMatch(/^functions +Every function/m);
|
|
188
246
|
expect(stdout).toMatch(/^schemas +/m);
|
|
189
247
|
expect(stdout).toMatch(/^enums +/m);
|
|
190
248
|
// One level only: no function is listed on the api page.
|
|
@@ -216,25 +274,57 @@ describe('the docs tree, one level at a time', () => {
|
|
|
216
274
|
expect(JSON.parse(both.stdout).code).toBe('ERR_INVALID_ARGUMENT');
|
|
217
275
|
}, SLOW);
|
|
218
276
|
|
|
219
|
-
it('reads the integration
|
|
220
|
-
|
|
277
|
+
it('reads the integration guides by their routes, and not by the old name', async () => {
|
|
278
|
+
// cli/integrations is a namespace: one level, its guides by slot.
|
|
279
|
+
const level = await runCli(['docs', 'cli/integrations']);
|
|
280
|
+
expect(level.status).toBe(0);
|
|
281
|
+
expect(level.stdout).toMatch(
|
|
282
|
+
/^quick-start +Create a new integration package/m,
|
|
283
|
+
);
|
|
284
|
+
expect(level.stdout).toMatch(/^building-blocks +/m);
|
|
285
|
+
const guide = await runCli([
|
|
286
|
+
'docs',
|
|
287
|
+
'cli/integrations/building-blocks/codemods',
|
|
288
|
+
'--index',
|
|
289
|
+
]);
|
|
221
290
|
expect(guide.status).toBe(0);
|
|
222
|
-
expect(guide.stdout).toMatch(
|
|
291
|
+
expect(guide.stdout).toMatch(
|
|
292
|
+
/Read one section: .*docs cli\/integrations\/building-blocks\/codemods <section>/,
|
|
293
|
+
);
|
|
223
294
|
// A bare read is one level too: the sections, and how to read it all.
|
|
224
|
-
const bare = await runCli([
|
|
295
|
+
const bare = await runCli([
|
|
296
|
+
'docs',
|
|
297
|
+
'cli/integrations/building-blocks/codemods',
|
|
298
|
+
]);
|
|
225
299
|
expect(bare.status).toBe(0);
|
|
226
300
|
expect(bare.stdout).toBe(guide.stdout);
|
|
227
|
-
expect(bare.stdout).toMatch(
|
|
228
|
-
|
|
301
|
+
expect(bare.stdout).toMatch(
|
|
302
|
+
/Read everything: +.*docs cli\/integrations\/building-blocks\/codemods --full$/m,
|
|
303
|
+
);
|
|
304
|
+
const one = await runCli([
|
|
305
|
+
'docs',
|
|
306
|
+
'cli/integrations/building-blocks/codemods',
|
|
307
|
+
'which-codemods-run',
|
|
308
|
+
]);
|
|
229
309
|
expect(one.status).toBe(0);
|
|
230
|
-
expect(one.stdout).toMatch(/^##
|
|
231
|
-
expect(one.stdout).toMatch(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
310
|
+
expect(one.stdout).toMatch(/^## Choose when a codemod runs$/m);
|
|
311
|
+
expect(one.stdout).toMatch(
|
|
312
|
+
/^Up: .*docs cli\/integrations\/building-blocks\/codemods --index$/m,
|
|
313
|
+
);
|
|
314
|
+
expect(one.stdout).toMatch(
|
|
315
|
+
/^Previous: .*docs cli\/integrations\/building-blocks\/codemods write-the-transform$/m,
|
|
316
|
+
);
|
|
317
|
+
expect(one.stdout).toMatch(
|
|
318
|
+
/^Next: .*docs cli\/integrations\/building-blocks\/codemods run-codemods-in-an-app$/m,
|
|
319
|
+
);
|
|
320
|
+
const full = await runCli([
|
|
321
|
+
'docs',
|
|
322
|
+
'cli/integrations/building-blocks/codemods',
|
|
323
|
+
'--full',
|
|
324
|
+
]);
|
|
235
325
|
expect(full.status).toBe(0);
|
|
236
|
-
expect(full.stdout).toMatch(/^##
|
|
237
|
-
expect(full.stdout.length).toBeGreaterThan(bare.stdout.length *
|
|
326
|
+
expect(full.stdout).toMatch(/^## Add a codemod$/m);
|
|
327
|
+
expect(full.stdout.length).toBeGreaterThan(bare.stdout.length * 2);
|
|
238
328
|
const old = await runCli(['docs', 'cli-integrations']);
|
|
239
329
|
expect(old.status).toBe(1);
|
|
240
330
|
expect(old.stderr).toContain('Unknown topic "cli-integrations"');
|
|
@@ -251,12 +341,11 @@ describe('the docs tree, one level at a time', () => {
|
|
|
251
341
|
expect(section.status).toBe(1);
|
|
252
342
|
const error = JSON.parse(section.stdout);
|
|
253
343
|
expect(error).toMatchObject({code: 'ERR_UNKNOWN_SECTION'});
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
]);
|
|
344
|
+
// It names the namespace's children, in the order its slots list them.
|
|
345
|
+
expect(error.suggestions.map(s => s.name)).toEqual(
|
|
346
|
+
node.data.slots.flatMap(slot => slot.children.map(child => child.route)),
|
|
347
|
+
);
|
|
348
|
+
expect(error.suggestions.map(s => s.name)).toContain('cli/commands');
|
|
260
349
|
}, SLOW);
|
|
261
350
|
});
|
|
262
351
|
|
|
@@ -10,9 +10,10 @@ export const doc = {
|
|
|
10
10
|
namespace: 'cli/commands',
|
|
11
11
|
summary: 'Check an integration\'s docs: the docs tree they add, every link, and overlaps with Core topics',
|
|
12
12
|
description:
|
|
13
|
-
'
|
|
13
|
+
'Checks the docs tree the package adds, every link in its docs, and overlaps with Core topics. ' +
|
|
14
|
+
'Intentional replacements and extensions are information. ' +
|
|
14
15
|
'A same-name topic without `replaces` or `extends` is an accidental conflict ' +
|
|
15
|
-
'and fails until the author declares the relationship or renames it.',
|
|
16
|
+
'and fails until the author declares the relationship or renames it. See {@link generic:check-your-docs}.',
|
|
16
17
|
fn: 'integrationDocConflicts',
|
|
17
18
|
args: [
|
|
18
19
|
{
|