@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
|
@@ -7,18 +7,19 @@
|
|
|
7
7
|
* lets an AI agent drive the entire CLI WITHOUT scraping `--help` text. It is
|
|
8
8
|
* to the CLI what an OpenAPI spec is to an HTTP API.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* Its per-command facts come from the command's own definitions: names,
|
|
11
|
+
* arguments and options from Commander metadata (program.commands, cmd.options,
|
|
12
|
+
* cmd.registeredArguments, cmd.description()); examples from its CommandDoc;
|
|
13
|
+
* response `type` discriminators from the returns of the FunctionDoc it wraps
|
|
14
|
+
* (both attached by `defineCommand`); `--json` support from the JSON_SUPPORTED
|
|
15
|
+
* allowlist in index.mjs. The hand-kept lists are CLI_LAYER_RESPONSE_TYPES,
|
|
16
|
+
* for envelopes no API function returns, and ROOT_RESPONSE_TYPES, for the two
|
|
17
|
+
* (help and version) that no single command owns.
|
|
15
18
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* appears in the manifest and every JSON-supported command has a response-type
|
|
21
|
-
* entry, so adding a command without describing it fails CI.
|
|
19
|
+
* Drift-guard tests (manifest.test.mjs) assert every registered command appears
|
|
20
|
+
* in the manifest, every JSON-supported command has response types, and the
|
|
21
|
+
* examples and response types equal the docs, so adding a command without
|
|
22
|
+
* describing it fails CI.
|
|
22
23
|
*
|
|
23
24
|
* DESIGN DECISION — manifest stays CLI-special; there is intentionally NO
|
|
24
25
|
* `api/manifest`. It describes the CLI's own Commander tree, so it takes the live
|
|
@@ -39,153 +40,27 @@ import {commandDocsOf} from './define-command.mjs';
|
|
|
39
40
|
import {doc as manifestDoc} from '../commands/manifest.doc.mjs';
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
43
|
+
* Envelopes the CLI layer builds itself, so the wrapped FunctionDoc cannot
|
|
44
|
+
* declare them: `manifest` wraps no API function, `theme build` batches several
|
|
45
|
+
* `themeBuild()` receipts, and `theme add` with no slug (or `--list`) answers
|
|
46
|
+
* with `themeListAvailable()`'s `theme.list` instead of calling `themeAdd()`.
|
|
47
|
+
* manifest.test.mjs fails once the wrapped FunctionDoc declares one of these, so
|
|
48
|
+
* the list only shrinks.
|
|
48
49
|
* @type {Record<string, string[]>}
|
|
49
50
|
*/
|
|
50
|
-
|
|
51
|
-
init: ['init.run', 'init.remove'],
|
|
52
|
-
component: [
|
|
53
|
-
'component.list',
|
|
54
|
-
'component.detail',
|
|
55
|
-
'component.detail.props',
|
|
56
|
-
'component.detail.source',
|
|
57
|
-
'component.detail.showcase',
|
|
58
|
-
'component.detail.blocks',
|
|
59
|
-
],
|
|
60
|
-
docs: [
|
|
61
|
-
'docs.list',
|
|
62
|
-
'docs.index',
|
|
63
|
-
'docs.detail',
|
|
64
|
-
'docs.detail.section',
|
|
65
|
-
'docs.node',
|
|
66
|
-
],
|
|
67
|
-
blog: ['blog.list', 'blog.detail'],
|
|
68
|
-
discover: [
|
|
69
|
-
'discover.list',
|
|
70
|
-
'discover.detail',
|
|
71
|
-
'discover.detail.doc',
|
|
72
|
-
'discover.search',
|
|
73
|
-
],
|
|
74
|
-
search: ['search'],
|
|
75
|
-
build: ['build.help', 'build.kit'],
|
|
76
|
-
swizzle: ['swizzle.list', 'swizzle.copy'],
|
|
77
|
-
'gap-report': ['gap-report.categories', 'gap-report.file'],
|
|
78
|
-
template: [
|
|
79
|
-
'template.list',
|
|
80
|
-
'template.show',
|
|
81
|
-
'template.skeleton',
|
|
82
|
-
'template.copy',
|
|
83
|
-
'template.cdn',
|
|
84
|
-
],
|
|
85
|
-
hook: ['hook.list', 'hook.detail', 'hook.detail.params'],
|
|
86
|
-
'theme build': ['theme.build', 'theme.build.check', 'theme.build.batch'],
|
|
87
|
-
'theme list': ['theme.list'],
|
|
88
|
-
'theme add': ['theme.list', 'theme.add'],
|
|
89
|
-
'theme template': ['theme.template'],
|
|
90
|
-
'theme targets': ['theme.targets'],
|
|
91
|
-
'theme palette generate': ['theme.palette.generate'],
|
|
92
|
-
'integration add': ['integration.add'],
|
|
93
|
-
'integration pack': ['integration.pack-check'],
|
|
94
|
-
upgrade: ['upgrade.list', 'upgrade.status', 'upgrade.run'],
|
|
51
|
+
const CLI_LAYER_RESPONSE_TYPES = {
|
|
95
52
|
manifest: ['manifest'],
|
|
96
|
-
|
|
97
|
-
'
|
|
98
|
-
'doctor integration templates': ['integration.template-conflicts'],
|
|
99
|
-
'doctor integration components': ['integration.component-conflicts'],
|
|
100
|
-
'doctor integration docs': ['integration.doc-conflicts'],
|
|
101
|
-
'layout expand': ['layout.expand'],
|
|
102
|
-
'layout check': ['layout.check'],
|
|
103
|
-
'layout grammar': ['layout.grammar'],
|
|
53
|
+
'theme build': ['theme.build.batch'],
|
|
54
|
+
'theme add': ['theme.list'],
|
|
104
55
|
};
|
|
105
56
|
|
|
106
57
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
58
|
+
* Response types no single command owns: `help` (a bare `astryx --json`, and
|
|
59
|
+
* `--help --json` on any command) and `version` (`astryx --version --json`).
|
|
60
|
+
* The response-types enum lists them beside the per-command response types.
|
|
61
|
+
* @type {readonly string[]}
|
|
109
62
|
*/
|
|
110
|
-
const
|
|
111
|
-
component: [
|
|
112
|
-
'astryx component',
|
|
113
|
-
'astryx component XDSButton',
|
|
114
|
-
'astryx component XDSButton --props --json',
|
|
115
|
-
],
|
|
116
|
-
docs: [
|
|
117
|
-
'astryx docs',
|
|
118
|
-
'astryx docs spacing --json',
|
|
119
|
-
'astryx docs theme',
|
|
120
|
-
'astryx docs theme quick-start',
|
|
121
|
-
'astryx docs cli/integrations --full',
|
|
122
|
-
],
|
|
123
|
-
discover: ['astryx discover --json'],
|
|
124
|
-
search: [
|
|
125
|
-
'astryx search modal --json',
|
|
126
|
-
'astryx search button --type component --json',
|
|
127
|
-
],
|
|
128
|
-
build: ['astryx build', 'astryx build "analytics dashboard" --json'],
|
|
129
|
-
swizzle: ['astryx swizzle XDSButton'],
|
|
130
|
-
'gap-report': [
|
|
131
|
-
'astryx gap-report --list-categories',
|
|
132
|
-
"astryx gap-report Button --category docs_gap --reason 'Missing keyboard example'",
|
|
133
|
-
],
|
|
134
|
-
template: [
|
|
135
|
-
'astryx template --json',
|
|
136
|
-
'astryx template dashboard ./src/app',
|
|
137
|
-
'astryx template --cdn',
|
|
138
|
-
],
|
|
139
|
-
hook: ['astryx hook', 'astryx hook useFocusTrap --json'],
|
|
140
|
-
'theme build': [
|
|
141
|
-
'astryx theme build ./src/themes/ocean.ts --out ./dist/ocean.css',
|
|
142
|
-
'astryx theme build ./src/themes/ocean.ts --check',
|
|
143
|
-
],
|
|
144
|
-
'theme list': ['astryx theme list --json'],
|
|
145
|
-
'theme add': [
|
|
146
|
-
'astryx theme add matcha',
|
|
147
|
-
'astryx theme add matcha ./src/themes/matcha',
|
|
148
|
-
],
|
|
149
|
-
'theme template': ['astryx theme template', 'astryx theme template --json'],
|
|
150
|
-
'theme targets': [
|
|
151
|
-
'astryx theme targets Switch',
|
|
152
|
-
'astryx --json theme targets',
|
|
153
|
-
],
|
|
154
|
-
'theme palette generate': [
|
|
155
|
-
'astryx theme palette generate palette.config.json',
|
|
156
|
-
'astryx theme palette generate palette.config.json --out ocean.palette.json',
|
|
157
|
-
],
|
|
158
|
-
'integration add': [
|
|
159
|
-
'astryx integration add component AcmeWidget',
|
|
160
|
-
'astryx integration add doc deploying --dry-run --json',
|
|
161
|
-
],
|
|
162
|
-
'integration pack': ['astryx integration pack --check --json'],
|
|
163
|
-
upgrade: ['astryx upgrade --json'],
|
|
164
|
-
manifest: ['astryx manifest --json', 'astryx --json'],
|
|
165
|
-
doctor: ['astryx doctor', 'astryx doctor --json'],
|
|
166
|
-
'doctor integration validate': [
|
|
167
|
-
'astryx doctor integration validate',
|
|
168
|
-
'astryx doctor integration validate @acme/widgets --json',
|
|
169
|
-
],
|
|
170
|
-
'doctor integration templates': [
|
|
171
|
-
'astryx doctor integration templates',
|
|
172
|
-
'astryx doctor integration templates @acme/widgets --json',
|
|
173
|
-
],
|
|
174
|
-
'doctor integration components': [
|
|
175
|
-
'astryx doctor integration components',
|
|
176
|
-
'astryx doctor integration components @acme/widgets --json',
|
|
177
|
-
],
|
|
178
|
-
'doctor integration docs': [
|
|
179
|
-
'astryx doctor integration docs',
|
|
180
|
-
'astryx doctor integration docs @acme/widgets --json',
|
|
181
|
-
],
|
|
182
|
-
init: ['astryx init', 'astryx init --all --json'],
|
|
183
|
-
'layout expand': [
|
|
184
|
-
`astryx layout expand 'V[g6] > C{card-callout}*4' ./src/Page.tsx`,
|
|
185
|
-
],
|
|
186
|
-
'layout check': [`astryx layout check 'A[cp6] > L > LC > S[p6]' --json`],
|
|
187
|
-
'layout grammar': ['astryx layout grammar'],
|
|
188
|
-
};
|
|
63
|
+
export const ROOT_RESPONSE_TYPES = Object.freeze(['help', 'version']);
|
|
189
64
|
|
|
190
65
|
/**
|
|
191
66
|
* Map a Commander Option to a flag descriptor. Derives type from whether the
|
|
@@ -301,11 +176,17 @@ function describeCommand(cmd, root, jsonSupported) {
|
|
|
301
176
|
const aliases = cmd.aliases ? cmd.aliases() : [];
|
|
302
177
|
if (aliases && aliases.length > 0) entry.aliases = [...aliases];
|
|
303
178
|
|
|
304
|
-
// Response types this command can emit in --json mode
|
|
305
|
-
//
|
|
306
|
-
|
|
179
|
+
// Response types this command can emit in --json mode: the returns of the
|
|
180
|
+
// FunctionDoc it wraps, then any envelope the CLI layer builds. Subcommand
|
|
181
|
+
// groups (e.g. bare `theme`) have none.
|
|
182
|
+
const responseTypes = [
|
|
183
|
+
...(docs?.fn?.returns ?? []).map(r => r.type),
|
|
184
|
+
...(CLI_LAYER_RESPONSE_TYPES[name] ?? []),
|
|
185
|
+
];
|
|
186
|
+
if (responseTypes.length > 0) entry.responseTypes = responseTypes;
|
|
307
187
|
|
|
308
|
-
|
|
188
|
+
const examples = (docs?.doc.examples ?? []).map(e => e.cli);
|
|
189
|
+
if (examples.length > 0) entry.examples = examples;
|
|
309
190
|
|
|
310
191
|
const exitCodes = (docs?.doc.exitCodes ?? []).map(({code, when}) => ({
|
|
311
192
|
code,
|
|
@@ -348,6 +229,15 @@ function describeGlobalOptions(program) {
|
|
|
348
229
|
return opts;
|
|
349
230
|
}
|
|
350
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Every command in a described tree, depth first.
|
|
234
|
+
* @param {any[]} commands
|
|
235
|
+
* @returns {any[]}
|
|
236
|
+
*/
|
|
237
|
+
function flattenCommands(commands) {
|
|
238
|
+
return commands.flatMap(c => [c, ...flattenCommands(c.subcommands || [])]);
|
|
239
|
+
}
|
|
240
|
+
|
|
351
241
|
/**
|
|
352
242
|
* Build the full capability manifest from a configured Commander program.
|
|
353
243
|
*
|
|
@@ -378,7 +268,9 @@ export function buildManifest(program, opts = {}) {
|
|
|
378
268
|
// Flat index of every response `type` discriminator the CLI can emit,
|
|
379
269
|
// keyed by command — lets an agent know what to expect back per call.
|
|
380
270
|
responseTypes: Object.fromEntries(
|
|
381
|
-
|
|
271
|
+
flattenCommands(commands)
|
|
272
|
+
.filter(c => c.responseTypes)
|
|
273
|
+
.map(c => [c.name, [...c.responseTypes]]),
|
|
382
274
|
),
|
|
383
275
|
};
|
|
384
276
|
}
|
|
@@ -14,11 +14,46 @@
|
|
|
14
14
|
* surfaces emit valid, enriched JSON.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import * as fs from 'node:fs';
|
|
18
|
+
import * as os from 'node:os';
|
|
19
|
+
import * as path from 'node:path';
|
|
20
|
+
import {fileURLToPath, pathToFileURL} from 'node:url';
|
|
17
21
|
import {describe, it, expect} from 'vitest';
|
|
18
22
|
import {program, JSON_SUPPORTED} from '../index.mjs';
|
|
19
|
-
import {buildManifest
|
|
23
|
+
import {buildManifest} from './manifest.mjs';
|
|
20
24
|
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
21
25
|
|
|
26
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Import every `*.doc.mjs` under `dir` whose doc has the given type, keyed by
|
|
30
|
+
* its `name`.
|
|
31
|
+
* @param {string} dir @param {string} type @returns {Promise<Map<string, any>>}
|
|
32
|
+
*/
|
|
33
|
+
async function loadDocs(dir, type) {
|
|
34
|
+
const out = new Map();
|
|
35
|
+
for (const entry of fs.readdirSync(dir, {withFileTypes: true, recursive: true})) {
|
|
36
|
+
if (!entry.isFile() || !entry.name.endsWith('.doc.mjs')) continue;
|
|
37
|
+
const file = path.join(entry.parentPath, entry.name);
|
|
38
|
+
const {doc} = await import(pathToFileURL(file).href);
|
|
39
|
+
if (doc?.type === type) out.set(doc.name, doc);
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const commandDocs = await loadDocs(path.join(HERE, '../commands'), 'command');
|
|
45
|
+
const functionDocs = await loadDocs(path.join(HERE, '../../../api'), 'function');
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Envelopes built in the CLI layer, which no FunctionDoc can declare. Pinned so
|
|
49
|
+
* an entry is dropped once its type moves behind an API function.
|
|
50
|
+
*/
|
|
51
|
+
const CLI_LAYER_TYPES = {
|
|
52
|
+
manifest: ['manifest'],
|
|
53
|
+
'theme build': ['theme.build.batch'],
|
|
54
|
+
'theme add': ['theme.list'],
|
|
55
|
+
};
|
|
56
|
+
|
|
22
57
|
const manifest = buildManifest(program, {jsonSupported: JSON_SUPPORTED, version: '0.0.0-test'});
|
|
23
58
|
|
|
24
59
|
/** Flatten the manifest command tree into fully-qualified names. */
|
|
@@ -64,17 +99,73 @@ describe('manifest: drift guards', () => {
|
|
|
64
99
|
|
|
65
100
|
it('declares response types for every JSON-supported command', () => {
|
|
66
101
|
for (const name of JSON_SUPPORTED) {
|
|
102
|
+
const entry = allEntries.find((c) => c.name === name);
|
|
67
103
|
expect(
|
|
68
|
-
|
|
69
|
-
`JSON-supported command "${name}" has no response
|
|
70
|
-
).
|
|
71
|
-
expect(
|
|
104
|
+
entry?.responseTypes?.length,
|
|
105
|
+
`JSON-supported command "${name}" has no response types`,
|
|
106
|
+
).toBeGreaterThan(0);
|
|
107
|
+
expect(manifest.responseTypes[name]).toEqual(entry.responseTypes);
|
|
72
108
|
}
|
|
73
109
|
});
|
|
74
110
|
|
|
75
111
|
it('has no response-type entry for a command that does not exist', () => {
|
|
76
|
-
for (const name of Object.keys(
|
|
77
|
-
expect(allNames.has(name), `
|
|
112
|
+
for (const name of Object.keys(manifest.responseTypes)) {
|
|
113
|
+
expect(allNames.has(name), `responseTypes key "${name}" is not a real command`).toBe(true);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('takes every command example from its CommandDoc', () => {
|
|
118
|
+
for (const [name, doc] of commandDocs) {
|
|
119
|
+
const entry = allEntries.find((c) => c.name === name);
|
|
120
|
+
expect(entry, `CommandDoc "${name}" has no manifest entry`).toBeDefined();
|
|
121
|
+
expect(entry.examples ?? [], name).toEqual((doc.examples ?? []).map((e) => e.cli));
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('lists every response type the wrapped API function returns', () => {
|
|
126
|
+
for (const [name, doc] of commandDocs) {
|
|
127
|
+
if (!doc.fn) continue;
|
|
128
|
+
const entry = allEntries.find((c) => c.name === name);
|
|
129
|
+
for (const {type} of functionDocs.get(doc.fn).returns) {
|
|
130
|
+
expect(entry.responseTypes, `${name} can emit ${type}`).toContain(type);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('lists upgrade.registry, which `upgrade --registry --json` emits', async () => {
|
|
136
|
+
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-manifest-'));
|
|
137
|
+
fs.writeFileSync(path.join(cwd, 'package.json'), '{"name":"app","version":"1.0.0"}');
|
|
138
|
+
const {status, stdout} = await runCli(['--json', 'upgrade', '--registry'], {cwd});
|
|
139
|
+
expect(status).toBe(0);
|
|
140
|
+
expect(JSON.parse(stdout).type).toBe('upgrade.registry');
|
|
141
|
+
expect(manifest.responseTypes.upgrade).toContain('upgrade.registry');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('lists theme.list for theme add, which lists themes when given no slug', async () => {
|
|
145
|
+
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-manifest-'));
|
|
146
|
+
fs.writeFileSync(path.join(cwd, 'package.json'), '{"name":"app","version":"1.0.0"}');
|
|
147
|
+
const {status, stdout} = await runCli(['--json', 'theme', 'add'], {cwd});
|
|
148
|
+
expect(status).toBe(0);
|
|
149
|
+
expect(JSON.parse(stdout).type).toBe('theme.list');
|
|
150
|
+
expect(manifest.responseTypes['theme add']).toContain('theme.list');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('takes response types from the wrapped FunctionDoc, plus CLI-layer envelopes', () => {
|
|
154
|
+
for (const [name, doc] of commandDocs) {
|
|
155
|
+
const entry = allEntries.find((c) => c.name === name);
|
|
156
|
+
const returns = doc.fn ? functionDocs.get(doc.fn).returns.map((r) => r.type) : [];
|
|
157
|
+
const expected = [...returns, ...(CLI_LAYER_TYPES[name] ?? [])];
|
|
158
|
+
expect(entry.responseTypes ?? [], name).toEqual(expected);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('pins only CLI-layer envelopes that no FunctionDoc declares', () => {
|
|
163
|
+
for (const [name, types] of Object.entries(CLI_LAYER_TYPES)) {
|
|
164
|
+
const fn = commandDocs.get(name)?.fn;
|
|
165
|
+
const declared = fn ? functionDocs.get(fn).returns.map((r) => r.type) : [];
|
|
166
|
+
for (const type of types) {
|
|
167
|
+
expect(declared, `${type} is declared by ${fn}(); unpin it`).not.toContain(type);
|
|
168
|
+
}
|
|
78
169
|
}
|
|
79
170
|
});
|
|
80
171
|
|
|
@@ -156,7 +247,10 @@ describe('manifest: shape', () => {
|
|
|
156
247
|
|
|
157
248
|
it('derives arguments from Commander metadata', () => {
|
|
158
249
|
const component = allEntries.find((c) => c.name === 'component');
|
|
159
|
-
|
|
250
|
+
const names = component.arguments.find((a) => a.name === 'names');
|
|
251
|
+
expect(names.required).toBe(false);
|
|
252
|
+
expect(names.variadic).toBe(true);
|
|
253
|
+
expect(names.description).toContain('Two or more return one ordered batch');
|
|
160
254
|
const themeBuild = allEntries.find((c) => c.name === 'theme build');
|
|
161
255
|
expect(themeBuild.arguments.map((a) => a.name)).toContain('files');
|
|
162
256
|
const files = themeBuild.arguments.find((a) => a.name === 'files');
|
|
@@ -193,7 +287,7 @@ describe('manifest: e2e', () => {
|
|
|
193
287
|
// Enriched: the full structured manifest is embedded.
|
|
194
288
|
expect(parsed.data.manifest).toBeDefined();
|
|
195
289
|
expect(parsed.data.manifest.commands.find((c) => c.name === 'component').responseTypes)
|
|
196
|
-
.
|
|
290
|
+
.toEqual(expect.arrayContaining(['component.list', 'component.batch']));
|
|
197
291
|
});
|
|
198
292
|
});
|
|
199
293
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file A parse failure reads like every other Astryx error in text mode.
|
|
5
|
+
*
|
|
6
|
+
* `astryx theme list --lang zh-Hans` printed Commander's own line —
|
|
7
|
+
* `error: option '--lang <locale>' argument 'zh-Hans' is invalid…` — while
|
|
8
|
+
* every other CLI error prints `Error: …`. `--json` was already correct
|
|
9
|
+
* (ERR_INVALID_LANG), so text and JSON disagreed on everything except the exit
|
|
10
|
+
* code. Commander writes that line before any Astryx code runs, so the shim is
|
|
11
|
+
* the only place that can speak for it.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {describe, it, expect} from 'vitest';
|
|
15
|
+
import {Command} from 'commander';
|
|
16
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
17
|
+
import {installJsonShim} from './json-shim.mjs';
|
|
18
|
+
|
|
19
|
+
describe('a parse error prints the Astryx error format', () => {
|
|
20
|
+
it.each([
|
|
21
|
+
['invalid --lang value', ['theme', 'list', '--lang', 'zh-Hans'], 'ERR_INVALID_LANG'],
|
|
22
|
+
['invalid --detail value', ['theme', 'list', '--detail', 'nope'], 'ERR_INVALID_DETAIL'],
|
|
23
|
+
['unknown option', ['component', '--bogus-flag'], 'ERR_INVALID_OPTION'],
|
|
24
|
+
['missing argument', ['theme', 'build'], 'ERR_MISSING_ARGUMENT'],
|
|
25
|
+
])('%s', async (_label, args, code) => {
|
|
26
|
+
const human = await runCli(args);
|
|
27
|
+
|
|
28
|
+
expect(human.status).toBe(1);
|
|
29
|
+
expect(human.stderr).toContain('Error: ');
|
|
30
|
+
// Commander's own lowercase line must not reach the user.
|
|
31
|
+
expect(human.stderr).not.toMatch(/(^|\n)error: /);
|
|
32
|
+
|
|
33
|
+
// --json is unchanged, and the two modes agree on the exit code.
|
|
34
|
+
const json = await runCli(['--json', ...args]);
|
|
35
|
+
expect(json.status).toBe(human.status);
|
|
36
|
+
expect(JSON.parse(json.stdout).code).toBe(code);
|
|
37
|
+
expect(json.stderr).toBe('');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('carries Commander\'s explanation, not just a generic line', async () => {
|
|
41
|
+
const {stderr} = await runCli(['theme', 'list', '--lang', 'zh-Hans']);
|
|
42
|
+
expect(stderr).toContain("'zh-Hans' is invalid");
|
|
43
|
+
expect(stderr).toContain('en, zh, dense');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('leaves --help and --version at exit 0 with nothing on stderr', async () => {
|
|
47
|
+
for (const args of [['--help'], ['theme', '--help']]) {
|
|
48
|
+
const r = await runCli(args);
|
|
49
|
+
expect(r.status).toBe(0);
|
|
50
|
+
expect(r.stderr).toBe('');
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Commander writes help through the same stderr channel when it shows help
|
|
55
|
+
// BECAUSE the invocation failed, so suppressing that channel wholesale would
|
|
56
|
+
// have taken the help with it. Driven on a throwaway program rather than a
|
|
57
|
+
// real command, so the guard outlives whichever command happens to have a
|
|
58
|
+
// subcommand group today.
|
|
59
|
+
it('still lets help reach stderr when help IS the failure report', () => {
|
|
60
|
+
const program = new Command('probe');
|
|
61
|
+
const group = program.command('group');
|
|
62
|
+
group.command('leaf').action(() => {});
|
|
63
|
+
installJsonShim(program);
|
|
64
|
+
|
|
65
|
+
/** @type {string[]} */
|
|
66
|
+
const written = [];
|
|
67
|
+
const original = process.stderr.write;
|
|
68
|
+
// @ts-expect-error test double for the write signature
|
|
69
|
+
process.stderr.write = str => {
|
|
70
|
+
written.push(String(str));
|
|
71
|
+
return true;
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
group.outputHelp({error: true});
|
|
75
|
+
} finally {
|
|
76
|
+
process.stderr.write = original;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
expect(written.join('')).toMatch(/Usage: probe group/);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -491,7 +491,7 @@ export function generateCompressedIndex(
|
|
|
491
491
|
}
|
|
492
492
|
lines.push(' docs cli commands, API reference, integration authoring (one level at a time)');
|
|
493
493
|
lines.push(' swizzle <Name> eject component source for deep customization');
|
|
494
|
-
lines.push(' upgrade --apply
|
|
494
|
+
lines.push(' upgrade --from <old version> --apply run after any Astryx or integration dependency bump');
|
|
495
495
|
const appendCount = agentDocs.reduce(
|
|
496
496
|
(count, contribution) => count + contribution.append.length,
|
|
497
497
|
0,
|
|
@@ -105,7 +105,8 @@ describe('generateCompressedIndex', () => {
|
|
|
105
105
|
|
|
106
106
|
it('includes upgrade command and migration rule', () => {
|
|
107
107
|
const result = generateCompressedIndex('1.0.0');
|
|
108
|
-
|
|
108
|
+
// `upgrade --apply` alone stops with "Missing required --from".
|
|
109
|
+
expect(result).toContain('upgrade --from <old version> --apply');
|
|
109
110
|
expect(result).toMatch(/after any Astryx or integration dependency bump/);
|
|
110
111
|
});
|
|
111
112
|
|
|
@@ -201,7 +202,7 @@ describe('generateCompressedIndex', () => {
|
|
|
201
202
|
],
|
|
202
203
|
});
|
|
203
204
|
|
|
204
|
-
expect(result.indexOf('upgrade --apply')).toBeLessThan(
|
|
205
|
+
expect(result.indexOf('upgrade --from <old version> --apply')).toBeLessThan(
|
|
205
206
|
result.indexOf('INTEGRATIONS:'),
|
|
206
207
|
);
|
|
207
208
|
expect(result.indexOf('INTEGRATIONS:')).toBeLessThan(
|
|
@@ -63,7 +63,9 @@ describe('authoring self-docs', () => {
|
|
|
63
63
|
describe('what the authoring docs say about the docs tree', () => {
|
|
64
64
|
it('marks exactly the fields the docs tree does not read yet', () => {
|
|
65
65
|
const notReadYet = graphFieldsDoc.fields
|
|
66
|
-
.filter(field =>
|
|
66
|
+
.filter(field =>
|
|
67
|
+
/^Reserved: .*Nothing reads it today/.test(field.description),
|
|
68
|
+
)
|
|
67
69
|
.map(field => field.name);
|
|
68
70
|
// The tree reads `placement` for every guide (spec:AST-046); the other
|
|
69
71
|
// graph fields are still refused by every topic reader.
|
|
@@ -79,7 +81,9 @@ describe('what the authoring docs say about the docs tree', () => {
|
|
|
79
81
|
expect(placement.description).toMatch(
|
|
80
82
|
/Read for every guide, the CLI's and each integration's/,
|
|
81
83
|
);
|
|
82
|
-
expect(graphFieldsDoc.description).toMatch(
|
|
84
|
+
expect(graphFieldsDoc.description).toMatch(
|
|
85
|
+
/Nothing reads `aliases` or `audience` today/,
|
|
86
|
+
);
|
|
83
87
|
});
|
|
84
88
|
|
|
85
89
|
it('keeps graph blocks behind the separate GraphContentBlock type, and a section takes a reference block', () => {
|
|
@@ -315,12 +315,20 @@ function functionSection(fn, index) {
|
|
|
315
315
|
}
|
|
316
316
|
const params = fn.params ?? [];
|
|
317
317
|
if (params.length > 0) {
|
|
318
|
+
// A Default column only when some parameter declares a default, so a
|
|
319
|
+
// function with none keeps a three-column table.
|
|
320
|
+
const defaults = params.some(
|
|
321
|
+
(/** @type {any} */ p) => typeof p.default === 'string' && p.default !== '',
|
|
322
|
+
);
|
|
318
323
|
content.push({
|
|
319
324
|
type: 'table',
|
|
320
|
-
headers:
|
|
325
|
+
headers: defaults
|
|
326
|
+
? ['Parameter', 'Type', 'Default', 'Description']
|
|
327
|
+
: ['Parameter', 'Type', 'Description'],
|
|
321
328
|
rows: params.map((/** @type {any} */ p) => [
|
|
322
|
-
`\`${p.name}
|
|
329
|
+
`\`${p.name}\`${p.required ? ' (required)' : ''}`,
|
|
323
330
|
`\`${p.type ?? ''}\``,
|
|
331
|
+
...(defaults ? [p.default ?? ''] : []),
|
|
324
332
|
p.description ?? '',
|
|
325
333
|
]),
|
|
326
334
|
});
|
|
@@ -405,6 +413,12 @@ export function cliDocSection(doc, index) {
|
|
|
405
413
|
if (doc.type === 'command') return commandSection(doc, index);
|
|
406
414
|
if (doc.type === 'function') return functionSection(doc, index);
|
|
407
415
|
if (doc.type === 'enum') return enumSection(doc);
|
|
416
|
+
if (doc.type === 'namespace')
|
|
417
|
+
return {
|
|
418
|
+
id: routeSegment(doc.name),
|
|
419
|
+
title: doc.title,
|
|
420
|
+
content: doc.blocks ?? [],
|
|
421
|
+
};
|
|
408
422
|
return {...selfDocSection(doc), id: routeSegment(doc.name)};
|
|
409
423
|
}
|
|
410
424
|
|
|
@@ -315,6 +315,26 @@ describe('cliDocSection', () => {
|
|
|
315
315
|
]);
|
|
316
316
|
});
|
|
317
317
|
|
|
318
|
+
it('marks required parameters and adds a Default column when a parameter has a default', () => {
|
|
319
|
+
const beta = fn('beta', {
|
|
320
|
+
params: [
|
|
321
|
+
{name: 'slug', type: 'string', description: 'The slug.', required: true},
|
|
322
|
+
{name: 'options.limit', type: 'number', description: 'How many.', default: '20'},
|
|
323
|
+
],
|
|
324
|
+
});
|
|
325
|
+
const table = cliDocSection(beta, indexOf([beta])).content.find(
|
|
326
|
+
(/** @type {any} */ block) => block.type === 'table',
|
|
327
|
+
);
|
|
328
|
+
expect(table).toEqual({
|
|
329
|
+
type: 'table',
|
|
330
|
+
headers: ['Parameter', 'Type', 'Default', 'Description'],
|
|
331
|
+
rows: [
|
|
332
|
+
['`slug` (required)', '`string`', '', 'The slug.'],
|
|
333
|
+
['`options.limit`', '`number`', '20', 'How many.'],
|
|
334
|
+
],
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
318
338
|
it('renders an API function, an enum, and a schema', () => {
|
|
319
339
|
const alpha = fn('alpha', {
|
|
320
340
|
description: 'Longer.',
|
|
@@ -626,7 +626,11 @@ function findMergeTarget(sections, section) {
|
|
|
626
626
|
const sameTitle = sections.findIndex(
|
|
627
627
|
candidate => sourceTitle(candidate) === title,
|
|
628
628
|
);
|
|
629
|
-
return sameTitle;
|
|
629
|
+
if (sameTitle !== -1) return sameTitle;
|
|
630
|
+
// A base section retitled later keeps its old key as its `id`, so an
|
|
631
|
+
// extension that still names it by the old title finds it by that id. A
|
|
632
|
+
// title variant of a section with no id stays a separate section.
|
|
633
|
+
return sections.findIndex(candidate => candidate.id === key);
|
|
630
634
|
}
|
|
631
635
|
|
|
632
636
|
/**
|
|
@@ -509,6 +509,27 @@ describe('mergeTopic', () => {
|
|
|
509
509
|
expect(base.sections[0].content[0].text).toBe('npm i');
|
|
510
510
|
});
|
|
511
511
|
|
|
512
|
+
it('finds a retitled base section by the key its old title derives', () => {
|
|
513
|
+
// A base section retitled later keeps its old key as its `id`; an
|
|
514
|
+
// extension that still names it by the old title replaces it.
|
|
515
|
+
const merged = mergeTopic(
|
|
516
|
+
{
|
|
517
|
+
...base,
|
|
518
|
+
sections: [
|
|
519
|
+
{id: 'quick-start', title: 'Wrap your app in a theme', content: []},
|
|
520
|
+
{id: 'tokens', title: 'Tokens', content: []},
|
|
521
|
+
],
|
|
522
|
+
},
|
|
523
|
+
{sections: [{title: 'Quick Start', content: []}]},
|
|
524
|
+
);
|
|
525
|
+
expect(merged.sections.map(section => [section.id, section.title])).toEqual(
|
|
526
|
+
[
|
|
527
|
+
['quick-start', 'Quick Start'],
|
|
528
|
+
['tokens', 'Tokens'],
|
|
529
|
+
],
|
|
530
|
+
);
|
|
531
|
+
});
|
|
532
|
+
|
|
512
533
|
it('replaces a section by stable ID even when its title changes', () => {
|
|
513
534
|
const merged = mergeTopic(
|
|
514
535
|
{
|
|
@@ -32,7 +32,7 @@ export function sectionTitleKey(title: unknown): string;
|
|
|
32
32
|
export function sectionKey(section: any): string;
|
|
33
33
|
/**
|
|
34
34
|
* A name as a docs-tree route segment: lowercase words joined by hyphens, so
|
|
35
|
-
* `integrationPackCheck` and `integration
|
|
35
|
+
* `integrationPackCheck` and `integration verify` both read naturally.
|
|
36
36
|
* @param {string} name
|
|
37
37
|
* @returns {string}
|
|
38
38
|
*/
|