@astryxdesign/cli 0.6.3 → 0.6.4-canary.10dd683
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 +194 -0
- package/README.md +117 -78
- package/api/blog/blog.doc.mjs +1 -0
- package/api/build/_adapter.d.mts +50 -0
- package/api/build/_adapter.mjs +60 -0
- package/api/build/build.doc.mjs +16 -9
- package/api/build/build.test.mjs +197 -8
- package/api/build/build.type.d.mts +91 -2
- package/api/build/build.type.mjs +52 -8
- package/api/build/help/help.d.mts +12 -5
- package/api/build/help/help.mjs +69 -6
- package/api/build/kit/kit.d.mts +4 -1
- package/api/build/kit/kit.mjs +165 -49
- package/api/build/kit/rank.d.mts +44 -0
- package/api/build/kit/rank.mjs +432 -0
- package/api/build/kit/rank.test.mjs +196 -0
- package/api/component/_adapter.d.mts +6 -12
- package/api/component/_adapter.mjs +20 -10
- package/api/component/component.doc.mjs +13 -3
- package/api/component/component.mjs +91 -14
- package/api/component/component.test.mjs +38 -0
- package/api/component/component.type.d.mts +22 -11
- package/api/component/component.type.mjs +32 -24
- package/api/component/detail/blocks/blocks.d.mts +2 -1
- package/api/component/detail/blocks/blocks.mjs +4 -3
- package/api/component/list/list.d.mts +0 -5
- package/api/component/list/list.mjs +40 -11
- 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 +62 -18
- package/api/discover/discover.mjs +220 -36
- package/api/discover/discover.test.mjs +11 -2
- package/api/discover/discover.type.d.mts +150 -11
- package/api/discover/discover.type.mjs +107 -17
- 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 +272 -41
- package/api/docs/_adapter.mjs +985 -108
- package/api/docs/compiled-topics.test.mjs +78 -0
- package/api/docs/detail/detail.mjs +22 -63
- package/api/docs/detail/section/section.d.mts +1 -1
- package/api/docs/detail/section/section.mjs +54 -19
- package/api/docs/detail/section/section.test.mjs +50 -0
- package/api/docs/docs.d.mts +10 -3
- package/api/docs/docs.doc.mjs +55 -16
- package/api/docs/docs.mjs +53 -10
- package/api/docs/docs.test.mjs +164 -4
- package/api/docs/docs.type.d.mts +221 -5
- package/api/docs/docs.type.mjs +153 -11
- package/api/docs/index/index.d.mts +18 -0
- package/api/docs/index/index.mjs +40 -0
- package/api/docs/index/index.test.mjs +62 -0
- package/api/docs/integration-tree.test.mjs +555 -0
- package/api/docs/integrationDocs.test.mjs +114 -8
- package/api/docs/list/list.mjs +28 -12
- package/api/docs/node/node.d.mts +43 -0
- package/api/docs/node/node.mjs +192 -0
- package/api/docs/reference-blocks.test.mjs +406 -0
- package/api/doctor/doctor.d.mts +99 -1
- package/api/doctor/doctor.doc.mjs +1 -0
- package/api/doctor/doctor.mjs +548 -1
- package/api/doctor/doctor.test.mjs +610 -1
- package/api/gap-report/gap-report.doc.mjs +8 -4
- package/api/hook/_adapter.mjs +19 -5
- package/api/hook/hook.doc.mjs +1 -0
- package/api/hook/hook.type.d.mts +3 -3
- package/api/hook/hook.type.mjs +11 -11
- package/api/hook/list/list.d.mts +2 -2
- package/api/hook/list/list.mjs +69 -17
- package/api/index.d.mts +1 -1
- package/api/index.mjs +1 -0
- package/api/init/init.doc.mjs +6 -1
- package/api/init/init.test.mjs +41 -1
- package/api/init/remove/remove.mjs +1 -1
- package/api/init/run/run.mjs +20 -10
- package/api/integration/add-contribution.component-names.test.mjs +120 -0
- package/api/integration/add-contribution.d.mts +2 -1
- package/api/integration/add-contribution.mjs +130 -15
- package/api/integration/add-contribution.test.mjs +258 -7
- package/api/integration/add-helpers.d.mts +5 -2
- package/api/integration/add-helpers.mjs +36 -9
- package/api/integration/add-theme.mjs +34 -64
- package/api/integration/add-theme.test.mjs +105 -21
- package/api/integration/authoring-checks.mjs +138 -28
- package/api/integration/authoring-checks.test.mjs +179 -7
- package/api/integration/authoring-checks.type.mjs +6 -1
- package/api/integration/integration-authoring.type.d.mts +3 -1
- package/api/integration/integration-authoring.type.mjs +2 -0
- package/api/integration/integration-block-exports.test.mjs +10 -6
- package/api/integration/integrationAdd.doc.mjs +14 -4
- package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
- package/api/integration/integrationAddCodemod.doc.mjs +1 -0
- package/api/integration/integrationAddComponent.doc.mjs +2 -1
- package/api/integration/integrationAddDoc.doc.mjs +8 -1
- package/api/integration/integrationAddTemplate.doc.mjs +1 -0
- package/api/integration/integrationAddTheme.doc.mjs +6 -5
- package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
- package/api/integration/integrationDocConflicts.doc.mjs +2 -1
- package/api/integration/integrationPackCheck.doc.mjs +2 -1
- package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
- package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
- package/api/integration/pack-check.mjs +83 -7
- package/api/integration/pack-check.test.mjs +387 -47
- package/api/integration/pack-check.type.d.mts +26 -2
- package/api/integration/pack-check.type.mjs +14 -1
- package/api/integration/summarizeIssues.doc.mjs +1 -0
- package/api/integration/template-conflict-compatibility.test.mjs +73 -0
- package/api/integration/validate-integration-fixes.test.mjs +1389 -0
- package/api/integration/validate-integration.mjs +52 -102
- package/api/integration/validate-integration.test.mjs +179 -26
- package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
- package/api/integration/validateIntegration.doc.mjs +3 -2
- package/api/json/assertResponse.doc.mjs +1 -0
- package/api/json/envelope-types.test.mjs +76 -0
- package/api/json/index.ts +2 -0
- package/api/json/isError.doc.mjs +1 -0
- package/api/json/parseResponse.doc.mjs +3 -2
- package/api/layout/_adapter.mjs +20 -5
- package/api/layout/expand/expand.mjs +7 -5
- package/api/layout/expand/expand.path-safety.test.mjs +53 -0
- package/api/layout/grammar/grammar.mjs +2 -1
- package/api/layout/layoutCheck.doc.mjs +1 -0
- package/api/layout/layoutExpand.doc.mjs +2 -1
- package/api/layout/layoutGrammar.doc.mjs +1 -0
- package/api/search/search-return-type.test.mjs +54 -0
- package/api/search/search.d.mts +62 -11
- package/api/search/search.doc.mjs +8 -2
- package/api/search/search.mjs +471 -83
- package/api/search/search.test.mjs +124 -1
- package/api/search/search.type.d.mts +15 -3
- package/api/search/search.type.mjs +5 -2
- package/api/swizzle/copy/copy.mjs +28 -11
- package/api/swizzle/swizzle.doc.mjs +2 -1
- package/api/swizzle/swizzle.type.d.mts +2 -2
- package/api/swizzle/swizzle.type.mjs +2 -2
- package/api/template/copy/copy.mjs +17 -23
- package/api/template/copy/copy.test.mjs +17 -0
- package/api/template/list/list.mjs +1 -0
- package/api/template/table-floating-bulk-actions.test.mjs +66 -0
- package/api/template/template-integration.test.mjs +1072 -3
- package/api/template/template-suffix.test.mjs +41 -21
- package/api/template/template.d.mts +1 -1
- package/api/template/template.doc.mjs +30 -8
- package/api/template/template.mjs +45 -8
- package/api/template/template.type.d.mts +12 -14
- package/api/template/template.type.mjs +15 -14
- package/api/theme/_adapter.d.mts +2 -3
- package/api/theme/_adapter.mjs +4 -5
- package/api/theme/add/add.binary.test.mjs +84 -0
- package/api/theme/add/add.mjs +31 -22
- package/api/theme/add/add.rollback.test.mjs +158 -0
- package/api/theme/add/add.staging.test.mjs +83 -0
- package/api/theme/add/add.test.mjs +14 -1
- package/api/theme/build/build.family.test.mjs +7 -12
- package/api/theme/build/build.mjs +140 -59
- package/api/theme/build/build.public-component-vars.test.mjs +1 -1
- package/api/theme/build/build.receipt-doc.test.mjs +111 -0
- package/api/theme/build/build.rollback.test.mjs +148 -0
- package/api/theme/build/build.test.mjs +127 -0
- package/api/theme/build/font-warning.mjs +3 -3
- package/api/theme/build/font-warning.test.mjs +5 -2
- package/api/theme/generateTonalPalette.doc.mjs +1 -0
- package/api/theme/integration-themes.test.mjs +39 -28
- package/api/theme/list/list.test.mjs +19 -20
- package/api/theme/listThemes.doc.mjs +6 -5
- package/api/theme/palette/generate/generate.mjs +8 -3
- package/api/theme/palette/generate/generate.test.mjs +96 -0
- package/api/theme/palette/generate/generator.d.mts +10 -13
- package/api/theme/palette/generate/generator.mjs +15 -4
- package/api/theme/palette/generate/generator.test.mjs +10 -0
- package/api/theme/template/template.mjs +11 -2
- package/api/theme/template/template.test.mjs +20 -0
- package/api/theme/theme.type.d.mts +170 -11
- package/api/theme/theme.type.mjs +94 -27
- package/api/theme/themeAdd.doc.mjs +4 -3
- package/api/theme/themeBuild.doc.mjs +8 -4
- package/api/theme/themeList.doc.mjs +6 -3
- package/api/theme/themeListAvailable.doc.mjs +5 -3
- package/api/theme/themePaletteGenerate.doc.mjs +1 -0
- package/api/theme/themeTargets.doc.mjs +1 -0
- package/api/theme/themeTemplate.doc.mjs +6 -2
- package/api/upgrade/_adapter.d.mts +32 -5
- package/api/upgrade/_adapter.mjs +139 -22
- package/api/upgrade/list/list.mjs +2 -1
- package/api/upgrade/list/list.test.mjs +73 -0
- package/api/upgrade/project-context.test.mjs +272 -0
- package/api/upgrade/provider-agreement.test.mjs +152 -0
- package/api/upgrade/run/run.mjs +356 -59
- package/api/upgrade/status/status.mjs +2 -2
- package/api/upgrade/upgrade.doc.mjs +12 -5
- package/api/upgrade/upgrade.type.d.mts +43 -5
- package/api/upgrade/upgrade.type.mjs +27 -11
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/__tests__/runner.test.mjs +330 -8
- package/assets/codemods/integration-discovery.mjs +48 -4
- package/assets/codemods/integration-discovery.test.mjs +73 -0
- package/assets/codemods/integration-runner.mjs +56 -4
- package/assets/codemods/integration-runner.protection.test.mjs +153 -0
- package/assets/codemods/registry.mjs +1 -0
- package/assets/codemods/run-codemod.mjs +177 -34
- package/assets/codemods/runner.mjs +350 -102
- package/assets/codemods/term-log.mjs +32 -8
- package/assets/codemods/term-log.test.mjs +19 -1
- package/assets/codemods/transform-prop.mjs +109 -0
- package/assets/codemods/transform-prop.test.mjs +95 -0
- package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
- package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
- package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
- package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
- package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
- package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
- package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
- package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
- package/assets/codemods/transforms/v0.6.4/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
- package/assets/codemods/transforms/v0.6.4/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
- package/assets/codemods/transforms/v0.6.4/index.mjs +31 -0
- package/assets/codemods/transforms/v0.6.4/migrate-native-picker-to-presentation.mjs +148 -0
- package/assets/codemods/transforms/v0.6.4/migrate-theme-catalog-to-descriptors.mjs +141 -0
- package/assets/docs/README.md +9 -0
- package/assets/docs/authoring.doc.mjs +14 -0
- package/assets/docs/getting-started.doc.mjs +2 -2
- package/assets/docs/internationalization.doc.mjs +7 -5
- package/assets/docs/layout.doc.dense.mjs +2 -2
- package/assets/docs/layout.doc.mjs +1 -1
- package/assets/docs/principles.doc.mjs +6 -6
- package/assets/docs/styling-libraries.doc.mjs +4 -4
- package/assets/docs/styling.doc.mjs +4 -4
- package/assets/docs/theme.doc.mjs +5 -5
- package/assets/docs/tokens.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +30 -0
- package/assets/docs/tree/cli.doc.mjs +23 -0
- package/assets/docs/tree/commands.doc.mjs +25 -0
- package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +144 -26
- package/assets/docs/tree/integrations.test.mjs +62 -0
- package/assets/docs/tree/writing-docs.doc.mjs +286 -0
- package/assets/docs/working-with-ai.doc.mjs +4 -4
- package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
- package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
- package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
- package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
- package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
- package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
- package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
- package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
- package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
- package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
- package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
- package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
- package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
- package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
- package/assets/templates/pages/table-tree/page.tsx +1704 -0
- package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
- package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
- package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
- package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
- package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
- package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
- package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
- package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
- package/authoring/_shared/contract.ts +22 -0
- package/authoring/codemod/codemod.doc.mjs +7 -2
- package/authoring/codemod/parse.d.mts +8 -8
- package/authoring/codemod/parse.mjs +8 -6
- package/authoring/codemod/type.ts +12 -0
- package/authoring/config/config.doc.mjs +10 -2
- package/authoring/config/debug-composition.test.mjs +92 -0
- package/authoring/config/parse.d.mts +15 -13
- package/authoring/config/parse.mjs +27 -8
- package/authoring/config/parse.test.mjs +8 -0
- package/authoring/config/type.ts +29 -6
- package/authoring/debug/debug.doc.d.mts +11 -0
- package/authoring/debug/debug.doc.mjs +182 -0
- package/authoring/debug/parse.d.mts +8 -8
- package/authoring/debug/parse.mjs +3 -3
- 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 +790 -23
- package/authoring/doctypes/_schema.mjs +543 -39
- package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
- package/authoring/doctypes/base/type.ts +41 -0
- package/authoring/doctypes/command/command.doc.mjs +4 -3
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +5 -4
- package/authoring/doctypes/component/component.doc.mjs +6 -3
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +6 -5
- package/authoring/doctypes/doctypes-new.test.mjs +48 -6
- package/authoring/doctypes/enum/enum.doc.mjs +1 -1
- package/authoring/doctypes/enum/parse.d.mts +2 -2
- package/authoring/doctypes/enum/parse.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +4 -2
- package/authoring/doctypes/function/function.doc.mjs +7 -2
- package/authoring/doctypes/function/parse.d.mts +2 -2
- package/authoring/doctypes/function/parse.mjs +1 -1
- package/authoring/doctypes/function/type.ts +9 -4
- package/authoring/doctypes/hook/hook.doc.mjs +4 -0
- package/authoring/doctypes/hook/parse.d.mts +2 -2
- package/authoring/doctypes/hook/parse.mjs +1 -1
- package/authoring/doctypes/hook/type.ts +5 -4
- package/authoring/doctypes/legacy.d.mts +8 -6
- package/authoring/doctypes/legacy.mjs +5 -4
- package/authoring/doctypes/load-contract.test.mjs +233 -0
- package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
- package/authoring/doctypes/namespace/parse.d.mts +12 -0
- package/authoring/doctypes/namespace/parse.mjs +25 -0
- package/authoring/doctypes/namespace/parse.test.mjs +163 -0
- package/authoring/doctypes/namespace/type.ts +74 -0
- package/authoring/doctypes/parse.d.mts +22 -18
- package/authoring/doctypes/parse.mjs +22 -11
- package/authoring/doctypes/parse.test.mjs +77 -3
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +8 -5
- package/authoring/doctypes/reference/reference.doc.mjs +48 -6
- package/authoring/doctypes/reference/type.ts +70 -7
- package/authoring/doctypes/schema/parse.d.mts +2 -2
- package/authoring/doctypes/schema/parse.mjs +1 -1
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +4 -4
- package/authoring/doctypes/template/parse.d.mts +94 -1
- package/authoring/doctypes/template/parse.mjs +40 -2
- package/authoring/doctypes/template/parse.test.mjs +26 -2
- package/authoring/doctypes/template/template.doc.mjs +13 -3
- package/authoring/doctypes/template/type.ts +13 -2
- package/authoring/doctypes/theme/parse.d.mts +35 -0
- package/authoring/doctypes/theme/parse.mjs +76 -0
- package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
- package/authoring/doctypes/theme/theme.doc.mjs +79 -0
- package/authoring/doctypes/theme/type.ts +42 -0
- package/authoring/doctypes/types.ts +12 -10
- package/authoring/gap-report/gap-report.doc.d.mts +12 -0
- package/authoring/gap-report/gap-report.doc.mjs +183 -0
- package/authoring/gap-report/parse.d.mts +10 -10
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/identity/identity.doc.d.mts +9 -0
- package/authoring/identity/identity.doc.mjs +61 -0
- package/authoring/identity/type.ts +132 -0
- package/authoring/index.d.mts +3 -0
- package/authoring/index.d.ts +62 -17
- package/authoring/index.mjs +4 -1
- package/authoring/integration/integration.doc.mjs +15 -8
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/parse.test.mjs +10 -1
- package/authoring/integration/schema.d.mts +6 -4
- package/authoring/integration/schema.mjs +9 -3
- package/authoring/integration/type.ts +19 -8
- package/authoring/shadcn/receipt.d.mts +6 -6
- package/clients/cli/__tests__/cliManifest.test.ts +27 -29
- package/clients/cli/command-load-failure.test.mjs +83 -0
- package/clients/cli/commands/blog.doc.mjs +1 -1
- package/clients/cli/commands/blog.mjs +23 -8
- package/clients/cli/commands/blog.test.mjs +42 -1
- package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
- package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
- package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
- package/clients/cli/commands/build-theme.mjs +16 -50
- package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
- package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
- package/clients/cli/commands/build.doc.mjs +16 -8
- package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
- package/clients/cli/commands/build.mjs +137 -114
- package/clients/cli/commands/build.playbook.test.mjs +75 -0
- package/clients/cli/commands/build.text-fields.test.mjs +81 -0
- package/clients/cli/commands/component/index.mjs +3 -8
- package/clients/cli/commands/component-ownership.test.mjs +3 -3
- package/clients/cli/commands/component-package.test.mjs +46 -0
- package/clients/cli/commands/component-resolution.test.mjs +21 -0
- package/clients/cli/commands/component.doc.mjs +1 -1
- package/clients/cli/commands/component.test.mjs +19 -0
- package/clients/cli/commands/detail-levels.test.mjs +2 -2
- package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
- package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
- package/clients/cli/commands/discover.doc.mjs +55 -9
- package/clients/cli/commands/discover.mjs +393 -118
- package/clients/cli/commands/discover.sources.test.mjs +267 -0
- package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
- package/clients/cli/commands/docs.doc.mjs +28 -6
- package/clients/cli/commands/docs.mjs +240 -26
- package/clients/cli/commands/docs.test.mjs +193 -1
- package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
- package/clients/cli/commands/doctor-integration.test.mjs +90 -8
- package/clients/cli/commands/doctor.doc.mjs +1 -1
- package/clients/cli/commands/doctor.mjs +59 -32
- package/clients/cli/commands/doctor.test.mjs +42 -0
- package/clients/cli/commands/gap-report.doc.mjs +17 -6
- package/clients/cli/commands/gap-report.test.mjs +72 -0
- package/clients/cli/commands/hook/index.mjs +7 -17
- package/clients/cli/commands/hook.doc.mjs +1 -1
- package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
- package/clients/cli/commands/init.doc.mjs +20 -9
- package/clients/cli/commands/init.flag-help.test.mjs +153 -0
- package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
- package/clients/cli/commands/integration-add.doc.mjs +32 -6
- package/clients/cli/commands/integration-authoring.test.mjs +13 -9
- package/clients/cli/commands/integration-pack.doc.mjs +1 -1
- package/clients/cli/commands/integration-real-world.test.mjs +3 -9
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/integration.mjs +1 -0
- package/clients/cli/commands/interactive-guard.test.mjs +101 -24
- package/clients/cli/commands/json-contract.test.mjs +33 -0
- package/clients/cli/commands/layout-check.doc.mjs +15 -4
- package/clients/cli/commands/layout-expand.doc.mjs +22 -5
- package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
- package/clients/cli/commands/layout.doc.mjs +3 -3
- package/clients/cli/commands/layout.mjs +21 -9
- package/clients/cli/commands/layout.path-help.test.mjs +33 -0
- package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
- package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
- package/clients/cli/commands/search.doc.mjs +7 -4
- package/clients/cli/commands/search.mjs +28 -9
- package/clients/cli/commands/search.test.mjs +75 -0
- package/clients/cli/commands/setup-nudge.test.mjs +6 -0
- package/clients/cli/commands/swizzle.doc.mjs +3 -2
- package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
- package/clients/cli/commands/template.doc.mjs +52 -13
- package/clients/cli/commands/template.flag-help.test.mjs +117 -0
- package/clients/cli/commands/template.mjs +4 -91
- package/clients/cli/commands/template.path-help.test.mjs +40 -0
- package/clients/cli/commands/text-json-parity.test.mjs +719 -0
- package/clients/cli/commands/theme-add.doc.mjs +4 -3
- package/clients/cli/commands/theme-build.doc.mjs +8 -7
- package/clients/cli/commands/theme-list.doc.mjs +2 -2
- package/clients/cli/commands/theme-palette-generate.doc.mjs +9 -5
- package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
- package/clients/cli/commands/theme-palette.doc.mjs +1 -1
- package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
- package/clients/cli/commands/theme-targets.doc.mjs +1 -1
- package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
- package/clients/cli/commands/theme-template.doc.mjs +2 -2
- package/clients/cli/commands/theme.doc.mjs +1 -1
- package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
- package/clients/cli/commands/upgrade.doc.mjs +22 -10
- package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
- package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
- package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
- package/clients/cli/commands/upgrade.mjs +29 -7
- package/clients/cli/formatters/index.mjs +164 -1
- package/clients/cli/formatters/index.test.mjs +97 -0
- package/clients/cli/index.mjs +21 -30
- package/clients/cli/latest-version-env.test.mjs +50 -0
- package/clients/cli/lib/cli-error.test.mjs +7 -0
- package/clients/cli/lib/component-format.mjs +9 -9
- package/clients/cli/lib/component-format.test.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +32 -6
- package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
- package/clients/cli/lib/exit-codes.test.mjs +97 -0
- package/clients/cli/lib/hook-format.mjs +19 -10
- package/clients/cli/lib/json-shim.mjs +38 -2
- package/clients/cli/lib/json-shim.test.mjs +83 -0
- package/clients/cli/lib/manifest.d.ts +2 -0
- package/clients/cli/lib/manifest.mjs +37 -2
- package/clients/cli/lib/manifest.test.mjs +17 -0
- package/foundation/agent-docs/agent-docs.d.mts +7 -2
- package/foundation/agent-docs/agent-docs.mjs +82 -12
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
- package/foundation/agent-docs/agent-docs.test.mjs +19 -1
- package/foundation/config/integration-debug.test.mjs +28 -3
- package/foundation/config/project-themes.test.mjs +11 -19
- package/foundation/config/project.d.mts +20 -11
- package/foundation/config/project.mjs +263 -91
- package/foundation/config/project.test.mjs +270 -21
- package/foundation/discovery/authoring-self-docs.d.mts +87 -0
- package/foundation/discovery/authoring-self-docs.mjs +237 -0
- package/foundation/discovery/authoring-self-docs.test.mjs +170 -0
- package/foundation/discovery/authoring-surface.d.mts +74 -0
- package/foundation/discovery/authoring-surface.mjs +525 -0
- package/foundation/discovery/authoring-surface.test.mjs +392 -0
- package/foundation/discovery/cli-self-docs.d.mts +119 -0
- package/foundation/discovery/cli-self-docs.mjs +490 -0
- package/foundation/discovery/cli-self-docs.test.mjs +375 -0
- package/foundation/discovery/component-discovery.d.mts +39 -1
- package/foundation/discovery/component-discovery.mjs +50 -1
- package/foundation/discovery/component-loader.d.mts +35 -38
- package/foundation/discovery/component-loader.mjs +53 -222
- package/foundation/discovery/docs-discovery.d.mts +119 -11
- package/foundation/discovery/docs-discovery.mjs +423 -108
- package/foundation/discovery/docs-discovery.test.mjs +365 -20
- package/foundation/discovery/docs-output-budget.d.mts +28 -0
- package/foundation/discovery/docs-output-budget.mjs +50 -0
- package/foundation/discovery/docs-section-key.d.mts +116 -0
- package/foundation/discovery/docs-section-key.mjs +322 -0
- package/foundation/discovery/docs-section-key.test.mjs +246 -0
- package/foundation/discovery/template-adapter.d.mts +113 -11
- package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
- package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
- package/foundation/discovery/template-adapter.mjs +774 -83
- package/foundation/discovery/template-adapter.test.mjs +57 -0
- package/foundation/discovery/template-conflict-release.d.mts +13 -0
- package/foundation/discovery/template-conflict-release.mjs +40 -0
- package/foundation/discovery/template-conflict-release.test.mjs +40 -0
- package/foundation/discovery/theme-discovery.d.mts +67 -7
- package/foundation/discovery/theme-discovery.mjs +916 -186
- package/foundation/discovery/theme-discovery.test.mjs +613 -219
- package/foundation/discovery/theming-targets.test.mjs +4 -0
- package/foundation/doc-compiler/bundle.d.mts +47 -0
- package/foundation/doc-compiler/bundle.mjs +278 -0
- package/foundation/doc-compiler/bundle.test.mjs +266 -0
- package/foundation/doc-compiler/compile.d.mts +343 -0
- package/foundation/doc-compiler/compile.mjs +558 -0
- package/foundation/doc-compiler/diagnostics.d.mts +126 -0
- package/foundation/doc-compiler/diagnostics.mjs +305 -0
- package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
- package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
- package/foundation/doc-compiler/import.d.mts +24 -0
- package/foundation/doc-compiler/import.mjs +59 -0
- package/foundation/doc-compiler/inputs.d.mts +102 -0
- package/foundation/doc-compiler/inputs.mjs +291 -0
- package/foundation/doc-compiler/inputs.test.mjs +299 -0
- package/foundation/doc-compiler/ir.d.mts +22 -0
- package/foundation/doc-compiler/ir.mjs +471 -0
- package/foundation/doc-compiler/lenses.d.mts +36 -0
- package/foundation/doc-compiler/lenses.mjs +173 -0
- package/foundation/doc-compiler/links.d.mts +162 -0
- package/foundation/doc-compiler/links.mjs +294 -0
- package/foundation/doc-compiler/links.test.mjs +192 -0
- package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
- package/foundation/doc-compiler/overlays.d.mts +37 -0
- package/foundation/doc-compiler/overlays.mjs +206 -0
- package/foundation/doc-compiler/parse-readable.d.mts +9 -0
- package/foundation/doc-compiler/parse-readable.mjs +29 -0
- package/foundation/doc-compiler/read.d.mts +127 -0
- package/foundation/doc-compiler/read.mjs +325 -0
- package/foundation/doc-compiler/read.test.mjs +313 -0
- package/foundation/doc-compiler/source.d.mts +33 -0
- package/foundation/doc-compiler/source.mjs +128 -0
- package/foundation/doc-compiler/tree.d.mts +288 -0
- package/foundation/doc-compiler/tree.mjs +876 -0
- package/foundation/doc-compiler/tree.test.mjs +598 -0
- package/foundation/fs/file-protection.d.mts +33 -0
- package/foundation/fs/file-protection.mjs +825 -0
- package/foundation/fs/file-protection.test.mjs +250 -0
- package/foundation/fs/module-loader.d.mts +1 -0
- package/foundation/fs/module-loader.mjs +50 -1
- package/foundation/fs/module-loader.stdout.test.mjs +332 -0
- package/foundation/fs/path-safety.d.mts +3 -2
- package/foundation/fs/path-safety.mjs +49 -19
- package/foundation/fs/path-safety.test.mjs +50 -0
- package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
- package/foundation/identity/provider-identity.d.mts +90 -0
- package/foundation/identity/provider-identity.mjs +320 -0
- package/foundation/identity/provider-identity.test.mjs +254 -0
- package/foundation/identity/providers.d.mts +7 -0
- package/foundation/identity/providers.mjs +16 -0
- package/foundation/integrations/autolink.d.mts +58 -1
- package/foundation/integrations/autolink.mjs +143 -45
- package/foundation/integrations/autolink.test.mjs +1 -1
- package/foundation/integrations/cli-requirement.d.mts +45 -0
- package/foundation/integrations/cli-requirement.mjs +154 -0
- package/foundation/integrations/cli-requirement.test.mjs +84 -0
- package/foundation/integrations/contribution-fixes.d.mts +145 -0
- package/foundation/integrations/contribution-fixes.mjs +1284 -0
- package/foundation/integrations/contribution-inventory.d.mts +3 -2
- package/foundation/integrations/contribution-inventory.mjs +27 -24
- package/foundation/integrations/contribution-inventory.test.mjs +86 -27
- package/foundation/integrations/integration-warnings.d.mts +9 -2
- package/foundation/integrations/integration-warnings.mjs +52 -21
- package/foundation/integrations/integration-warnings.test.mjs +74 -1
- package/foundation/integrations/integrations.d.mts +63 -3
- package/foundation/integrations/integrations.mjs +122 -9
- package/foundation/integrations/integrations.test.mjs +415 -1
- package/foundation/integrations/provider-conflicts.test.mjs +125 -0
- package/foundation/integrations/provider-ledger.test.mjs +275 -0
- package/foundation/integrations/provider-resolution.d.mts +152 -0
- package/foundation/integrations/provider-resolution.mjs +576 -0
- package/foundation/integrations/provider-resolution.test.mjs +369 -0
- package/foundation/integrations/theme-descriptor.d.mts +8 -0
- package/foundation/integrations/theme-descriptor.mjs +44 -0
- package/foundation/integrations/validate-contributions.d.mts +2 -0
- package/foundation/integrations/validate-contributions.mjs +131 -29
- package/foundation/response/base.d.ts +8 -4
- package/foundation/response/error-codes.d.mts +3 -1
- package/foundation/response/error-codes.d.ts +2 -0
- package/foundation/response/error-codes.doc.mjs +13 -4
- package/foundation/response/error-codes.mjs +8 -2
- package/foundation/response/error-codes.test.mjs +137 -10
- package/foundation/response/json-contract.test.mjs +57 -17
- package/foundation/response/json.d.mts +4 -2
- package/foundation/response/json.mjs +8 -10
- package/foundation/response/response-types.doc.d.mts +5 -1
- package/foundation/response/response-types.doc.mjs +41 -21
- package/foundation/response/response-types.doc.test.mjs +158 -0
- package/foundation/response/response.doc.mjs +1 -1
- package/foundation/text/string-utils.d.mts +8 -0
- package/foundation/text/string-utils.mjs +40 -10
- package/foundation/xle/expand.d.mts +2 -0
- package/foundation/xle/expand.mjs +4 -3
- package/foundation/xle/expand.test.mjs +54 -0
- package/foundation/xle/xle.test.mjs +13 -0
- package/package.json +10 -11
- package/assets/templates/themes/manifest.json +0 -95
- package/clients/cli/lib/update-check.mjs +0 -83
- package/clients/cli/lib/update-check.test.mjs +0 -137
- package/clients/cli/update-hint-commands.test.mjs +0 -54
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @file Subprocess no-hang tests
|
|
4
|
+
* @file Subprocess no-hang tests: the CLI never waits on stdin (INV1).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Every run gets a stdin pipe that stays open and silent, the way an agent's
|
|
7
|
+
* harness holds it. A prompt or a stdin read for control flow then blocks until
|
|
8
|
+
* the deadline, and the run ends with signal SIGTERM and status null. With stdin
|
|
9
|
+
* ignored or closed, the same read would see EOF at once and pass.
|
|
10
|
+
*
|
|
11
|
+
* Every command and group in the manifest runs once, with a placeholder for
|
|
12
|
+
* each required argument so its action is reached, plus the bare `astryx`.
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
15
|
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
14
|
-
import {spawnSync} from 'node:child_process';
|
|
16
|
+
import {spawn, spawnSync} from 'node:child_process';
|
|
15
17
|
import * as fs from 'node:fs';
|
|
16
18
|
import * as path from 'node:path';
|
|
17
19
|
import * as os from 'node:os';
|
|
@@ -19,37 +21,112 @@ import {fileURLToPath} from 'node:url';
|
|
|
19
21
|
|
|
20
22
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
23
|
const CLI = path.resolve(__dirname, '..', 'bin', 'astryx.mjs');
|
|
24
|
+
const DEADLINE_MS = 20_000;
|
|
25
|
+
// Keeps every run offline: `blog` fetches its feed when run bare.
|
|
26
|
+
const OFFLINE = `data:text/javascript,${encodeURIComponent(
|
|
27
|
+
"globalThis.fetch = () => Promise.reject(new TypeError('fetch failed'));",
|
|
28
|
+
)}`;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Run `node <argv>` with a stdin pipe that is never written or ended.
|
|
32
|
+
* @param {string[]} argv
|
|
33
|
+
* @param {string} cwd
|
|
34
|
+
* @param {number} [deadline]
|
|
35
|
+
* @returns {Promise<{status: number | null, signal: NodeJS.Signals | null, output: string}>}
|
|
36
|
+
*/
|
|
37
|
+
function runHeld(argv, cwd, deadline = DEADLINE_MS) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const child = spawn(process.execPath, argv, {
|
|
40
|
+
cwd,
|
|
41
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
42
|
+
env: {...process.env, FORCE_COLOR: '0', CI: ''},
|
|
43
|
+
});
|
|
44
|
+
// Never written or ended; a late EPIPE after exit is not a result.
|
|
45
|
+
child.stdin.on('error', () => {});
|
|
46
|
+
let output = '';
|
|
47
|
+
child.stdout.setEncoding('utf8').on('data', chunk => (output += chunk));
|
|
48
|
+
child.stderr.setEncoding('utf8').on('data', chunk => (output += chunk));
|
|
49
|
+
const timer = setTimeout(() => child.kill('SIGTERM'), deadline);
|
|
50
|
+
child.on('error', error => {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
reject(error);
|
|
53
|
+
});
|
|
54
|
+
child.on('close', (status, signal) => {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
resolve({status, signal, output});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
22
60
|
|
|
23
|
-
|
|
61
|
+
/**
|
|
62
|
+
* @param {string[]} args
|
|
63
|
+
* @param {string} cwd
|
|
64
|
+
*/
|
|
65
|
+
function runCli(args, cwd) {
|
|
66
|
+
return runHeld(['--import', OFFLINE, CLI, ...args], cwd);
|
|
67
|
+
}
|
|
24
68
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
69
|
+
/** @returns {Array<[string, string[]]>} */
|
|
70
|
+
function manifestInvocations() {
|
|
71
|
+
const manifest = spawnSync(process.execPath, [CLI, 'manifest', '--json'], {
|
|
28
72
|
encoding: 'utf8',
|
|
29
|
-
timeout: 20_000,
|
|
30
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
31
|
-
env: {...process.env, FORCE_COLOR: '0', CI: ''},
|
|
32
73
|
});
|
|
74
|
+
/** @type {string[][]} */
|
|
75
|
+
const invocations = [[]];
|
|
76
|
+
/** @param {any[]} commands */
|
|
77
|
+
const walk = commands => {
|
|
78
|
+
for (const command of commands) {
|
|
79
|
+
invocations.push([
|
|
80
|
+
...command.name.split(' '),
|
|
81
|
+
...command.arguments.filter((/** @type {any} */ a) => a.required).map(() => 'x'),
|
|
82
|
+
]);
|
|
83
|
+
walk(command.subcommands ?? []);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
walk(JSON.parse(manifest.stdout).data.commands);
|
|
87
|
+
return invocations.map(args => [['astryx', ...args].join(' '), args]);
|
|
33
88
|
}
|
|
34
89
|
|
|
35
|
-
|
|
36
|
-
|
|
90
|
+
describe('the harness holds stdin open', () => {
|
|
91
|
+
it('so a stdin read is reported as a hang', async () => {
|
|
92
|
+
const r = await runHeld(['-e', 'process.stdin.resume()'], os.tmpdir(), 1_000);
|
|
93
|
+
expect(r.signal).toBe('SIGTERM');
|
|
94
|
+
expect(r.status).toBeNull();
|
|
95
|
+
});
|
|
37
96
|
});
|
|
38
97
|
|
|
39
|
-
|
|
40
|
-
|
|
98
|
+
describe('every command exits without waiting on stdin', () => {
|
|
99
|
+
it.concurrent.for(manifestInvocations())('%s', async ([label, args], {expect}) => {
|
|
100
|
+
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-interactive-guard-'));
|
|
101
|
+
try {
|
|
102
|
+
const r = await runCli(args, cwd);
|
|
103
|
+
expect(r.signal, `${label} waited on stdin:\n${r.output.slice(-500)}`).toBeNull();
|
|
104
|
+
} finally {
|
|
105
|
+
fs.rmSync(cwd, {recursive: true, force: true});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
41
108
|
});
|
|
42
109
|
|
|
43
110
|
describe('init is non-interactive by default (no TTY needed)', () => {
|
|
44
|
-
|
|
45
|
-
|
|
111
|
+
let tmpDir;
|
|
112
|
+
|
|
113
|
+
beforeEach(() => {
|
|
114
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-interactive-guard-'));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
afterEach(() => {
|
|
118
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('runs cleanly (exit 0, no hang) and writes agent docs', async () => {
|
|
122
|
+
const r = await runCli(['init'], tmpDir);
|
|
46
123
|
expect(r.signal).toBeNull(); // did not hang
|
|
47
124
|
expect(r.status).toBe(0); // succeeded without a TTY
|
|
48
125
|
expect(fs.readdirSync(tmpDir).length).toBeGreaterThan(0); // wrote the cheat sheet
|
|
49
126
|
});
|
|
50
127
|
|
|
51
|
-
it('writes an agent-doc file containing the ASTRYX cheat-sheet marker', () => {
|
|
52
|
-
runCli(['init']);
|
|
128
|
+
it('writes an agent-doc file containing the ASTRYX cheat-sheet marker', async () => {
|
|
129
|
+
await runCli(['init'], tmpDir);
|
|
53
130
|
// init injects into existing agent-doc files if present, else creates AGENTS.md
|
|
54
131
|
const candidates = ['AGENTS.md', 'CLAUDE.md', '.cursorrules', path.join('.claude', 'CLAUDE.md')];
|
|
55
132
|
const doc = candidates.find(f => fs.existsSync(path.join(tmpDir, f)));
|
|
@@ -57,8 +134,8 @@ describe('init is non-interactive by default (no TTY needed)', () => {
|
|
|
57
134
|
expect(fs.readFileSync(path.join(tmpDir, doc), 'utf8')).toMatch(/ASTRYX:START/);
|
|
58
135
|
});
|
|
59
136
|
|
|
60
|
-
it('still runs --features agents non-interactively', () => {
|
|
61
|
-
const r = runCli(['init', '--features', 'agents']);
|
|
137
|
+
it('still runs --features agents non-interactively', async () => {
|
|
138
|
+
const r = await runCli(['init', '--features', 'agents'], tmpDir);
|
|
62
139
|
expect(r.signal).toBeNull();
|
|
63
140
|
expect(r.status).toBe(0);
|
|
64
141
|
expect(fs.readdirSync(tmpDir).length).toBeGreaterThan(0);
|
|
@@ -172,3 +172,36 @@ describe('--json contract: supported commands emit valid envelopes', () => {
|
|
|
172
172
|
expect(parsed.data.summary.fail).toBeGreaterThan(0);
|
|
173
173
|
});
|
|
174
174
|
});
|
|
175
|
+
|
|
176
|
+
describe('--json contract: the flag describes the envelopes it emits', () => {
|
|
177
|
+
/** @param {string} shape e.g. ` apiVersion, error, code, suggestions? ` */
|
|
178
|
+
const fields = shape => shape.split(',').map(f => f.trim().replace(/\?$/, ''));
|
|
179
|
+
|
|
180
|
+
it('names every field of the success and error envelopes', async () => {
|
|
181
|
+
const manifest = parseJson((await runCli(['manifest', '--json'], {cwd: tmpDir})).stdout);
|
|
182
|
+
const {description} = manifest.data.globalOptions.find(o => o.flag === '--json');
|
|
183
|
+
const match = /Success envelope: \{([^}]*)\}.*Error envelope: \{([^}]*)\}/.exec(description);
|
|
184
|
+
expect(match, description).not.toBeNull();
|
|
185
|
+
const [, success, error] = /** @type {RegExpExecArray} */ (match);
|
|
186
|
+
|
|
187
|
+
for (const key of Object.keys(manifest)) expect(fields(success)).toContain(key);
|
|
188
|
+
expect(fields(success)).toContain('meta');
|
|
189
|
+
|
|
190
|
+
// An unknown command's envelope carries every error field, suggestions included.
|
|
191
|
+
const failure = parseJson((await runCli(['bogus-cmd', '--json'], {cwd: tmpDir})).stdout);
|
|
192
|
+
expect(Object.keys(failure)).toContain('suggestions');
|
|
193
|
+
for (const key of Object.keys(failure)) expect(fields(error)).toContain(key);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('the CLI README describes the same envelopes', () => {
|
|
197
|
+
const readme = fs.readFileSync(new URL('../../../README.md', import.meta.url), 'utf8');
|
|
198
|
+
const line = readme
|
|
199
|
+
.split('\n')
|
|
200
|
+
.find(l => l.startsWith('- `--json`: Output as typed JSON envelope:'));
|
|
201
|
+
expect(line, 'README global --json line').toBeDefined();
|
|
202
|
+
const [success, error] = [...String(line).matchAll(/`\{([^}]*)\}`/g)].map(m => fields(m[1]));
|
|
203
|
+
expect(success).toEqual(expect.arrayContaining(['apiVersion', 'type', 'data', 'meta']));
|
|
204
|
+
expect(error).toEqual(expect.arrayContaining(['apiVersion', 'error', 'code', 'suggestions']));
|
|
205
|
+
expect(readme).toContain('{"apiVersion": 1, "type": "component.detail"');
|
|
206
|
+
});
|
|
207
|
+
});
|
|
@@ -13,7 +13,7 @@ export const doc = {
|
|
|
13
13
|
type: 'command',
|
|
14
14
|
name: 'layout check',
|
|
15
15
|
displayName: 'astryx layout check',
|
|
16
|
-
namespace: 'cli',
|
|
16
|
+
namespace: 'cli/commands',
|
|
17
17
|
summary:
|
|
18
18
|
'Validate a layout expression and echo canonical compact/outline forms',
|
|
19
19
|
description:
|
|
@@ -21,9 +21,20 @@ export const doc = {
|
|
|
21
21
|
'echoes it back in both canonical surfaces (compact and outline). An invalid but ' +
|
|
22
22
|
'parseable expression is reported with line/col and suggestions, and exits non-zero.',
|
|
23
23
|
fn: 'layoutCheck',
|
|
24
|
-
args: [
|
|
24
|
+
args: [
|
|
25
|
+
{
|
|
26
|
+
name: 'expression',
|
|
27
|
+
param: 'expression',
|
|
28
|
+
required: false,
|
|
29
|
+
description:
|
|
30
|
+
'The XLE/XLO expression. Pass - to read it from stdin; --file reads it from a file instead.',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
25
33
|
options: [
|
|
26
|
-
{
|
|
34
|
+
{
|
|
35
|
+
flag: '--file <file>',
|
|
36
|
+
description: 'Read the expression from a file (used instead of the argument when both are given)',
|
|
37
|
+
},
|
|
27
38
|
{
|
|
28
39
|
flag: '--form <form>',
|
|
29
40
|
param: 'options.form',
|
|
@@ -47,7 +58,7 @@ export const doc = {
|
|
|
47
58
|
{code: 0, when: 'the expression is valid'},
|
|
48
59
|
{
|
|
49
60
|
code: 1,
|
|
50
|
-
when: 'the expression is invalid or
|
|
61
|
+
when: 'the expression is invalid, empty or over 5 MB (from stdin or --file), has a syntax error, or a bad --form',
|
|
51
62
|
},
|
|
52
63
|
],
|
|
53
64
|
related: ['layout expand', 'layout grammar'],
|
|
@@ -13,7 +13,7 @@ export const doc = {
|
|
|
13
13
|
type: 'command',
|
|
14
14
|
name: 'layout expand',
|
|
15
15
|
displayName: 'astryx layout expand',
|
|
16
|
-
namespace: 'cli',
|
|
16
|
+
namespace: 'cli/commands',
|
|
17
17
|
summary: 'Expand a layout expression into validated XDS TSX',
|
|
18
18
|
description:
|
|
19
19
|
'Parses and validates a compressed XLE/XLO expression, then expands it into ' +
|
|
@@ -21,11 +21,28 @@ export const doc = {
|
|
|
21
21
|
'interactive controls, and splicing referenced blocks. Writes to a path, or returns the code.',
|
|
22
22
|
fn: 'layoutExpand',
|
|
23
23
|
args: [
|
|
24
|
-
{
|
|
25
|
-
|
|
24
|
+
{
|
|
25
|
+
name: 'expression',
|
|
26
|
+
param: 'expression',
|
|
27
|
+
required: false,
|
|
28
|
+
description:
|
|
29
|
+
'The XLE/XLO expression. Pass - to read it from stdin; --file reads it from a file instead.',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'path',
|
|
33
|
+
param: 'options.targetPath',
|
|
34
|
+
required: false,
|
|
35
|
+
description:
|
|
36
|
+
'Where to write the TSX, relative to the project root. A path that ends in .tsx, .ts, .jsx, .js, .mjs, .cjs, .css, .scss, .json, .md or .html is the file to write; ' +
|
|
37
|
+
'any other path is a directory, which receives <Name>.tsx (see --name). An existing file there is replaced. ' +
|
|
38
|
+
'Omit it to print the code.',
|
|
39
|
+
},
|
|
26
40
|
],
|
|
27
41
|
options: [
|
|
28
|
-
{
|
|
42
|
+
{
|
|
43
|
+
flag: '--file <file>',
|
|
44
|
+
description: 'Read the expression from a file (used instead of the argument when both are given)',
|
|
45
|
+
},
|
|
29
46
|
{
|
|
30
47
|
flag: '--form <form>',
|
|
31
48
|
param: 'options.form',
|
|
@@ -59,7 +76,7 @@ export const doc = {
|
|
|
59
76
|
{code: 0, when: 'success'},
|
|
60
77
|
{
|
|
61
78
|
code: 1,
|
|
62
|
-
when: 'a missing
|
|
79
|
+
when: 'a missing, empty or over-5 MB expression (from stdin or --file), a bad --name or --form, a parse/validation error, or a path escape',
|
|
63
80
|
},
|
|
64
81
|
],
|
|
65
82
|
related: ['layout check', 'layout grammar'],
|
|
@@ -13,7 +13,7 @@ export const doc = {
|
|
|
13
13
|
type: 'command',
|
|
14
14
|
name: 'layout grammar',
|
|
15
15
|
displayName: 'astryx layout grammar',
|
|
16
|
-
namespace: 'cli',
|
|
16
|
+
namespace: 'cli/commands',
|
|
17
17
|
summary:
|
|
18
18
|
'Print the XLE/XLO cheatsheet (alias table generated from this branch)',
|
|
19
19
|
description:
|
|
@@ -12,7 +12,7 @@ export const doc = {
|
|
|
12
12
|
type: 'command',
|
|
13
13
|
name: 'layout',
|
|
14
14
|
displayName: 'astryx layout',
|
|
15
|
-
namespace: 'cli',
|
|
15
|
+
namespace: 'cli/commands',
|
|
16
16
|
summary: 'Generate XDS layouts from compressed expressions (XLE/XLO)',
|
|
17
17
|
description:
|
|
18
18
|
'The layout command group. Running astryx layout with no subcommand prints the ' +
|
|
@@ -27,8 +27,8 @@ export const doc = {
|
|
|
27
27
|
},
|
|
28
28
|
],
|
|
29
29
|
exitCodes: [
|
|
30
|
-
{code: 0, when: '
|
|
31
|
-
{code: 1, when: 'an unknown subcommand'},
|
|
30
|
+
{code: 0, when: 'a subcommand succeeded, or --help'},
|
|
31
|
+
{code: 1, when: 'no subcommand (help is printed) or an unknown subcommand'},
|
|
32
32
|
],
|
|
33
33
|
related: ['template', 'build'],
|
|
34
34
|
};
|
|
@@ -59,6 +59,9 @@ import {NO_RESULT_SET, resultSet} from '../../../foundation/debug/index.mjs';
|
|
|
59
59
|
* @property {boolean} [loose]
|
|
60
60
|
*/
|
|
61
61
|
|
|
62
|
+
/** The largest layout expression read from --file or stdin. */
|
|
63
|
+
const MAX_EXPRESSION_BYTES = 5 * 1024 * 1024; // 5 MB
|
|
64
|
+
|
|
62
65
|
/**
|
|
63
66
|
* Resolve the expression from arg, --file, or stdin ('-').
|
|
64
67
|
* @param {string} [expr]
|
|
@@ -78,8 +81,7 @@ async function readExpression(expr, options = {}) {
|
|
|
78
81
|
code: ERROR_CODES.ERR_FILE_NOT_FOUND,
|
|
79
82
|
});
|
|
80
83
|
}
|
|
81
|
-
|
|
82
|
-
if (stat.size > MAX_FILE_SIZE) {
|
|
84
|
+
if (stat.size > MAX_EXPRESSION_BYTES) {
|
|
83
85
|
cliError(
|
|
84
86
|
`File "${options.file}" is too large (${(stat.size / 1024 / 1024).toFixed(1)} MB, max 5 MB)`,
|
|
85
87
|
{code: ERROR_CODES.ERR_FILE_NOT_FOUND},
|
|
@@ -100,9 +102,19 @@ async function readExpression(expr, options = {}) {
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
if (expr === '-') {
|
|
105
|
+
// Capped like --file: an endless stream must not be buffered whole.
|
|
103
106
|
/** @type {Buffer[]} */
|
|
104
107
|
const chunks = [];
|
|
105
|
-
|
|
108
|
+
let size = 0;
|
|
109
|
+
for await (const chunk of process.stdin) {
|
|
110
|
+
size += /** @type {Buffer} */ (chunk).length;
|
|
111
|
+
if (size > MAX_EXPRESSION_BYTES) {
|
|
112
|
+
cliError('The layout expression on stdin is too large (max 5 MB)', {
|
|
113
|
+
code: ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
chunks.push(/** @type {Buffer} */ (chunk));
|
|
117
|
+
}
|
|
106
118
|
return Buffer.concat(chunks).toString('utf-8');
|
|
107
119
|
}
|
|
108
120
|
return expr ?? '';
|
|
@@ -154,15 +166,15 @@ export function registerLayout(program) {
|
|
|
154
166
|
if (result.data.written) {
|
|
155
167
|
out.push(
|
|
156
168
|
text(`[ok] Expanded to ${result.data.written}`),
|
|
169
|
+
// Field names are the JSON keys; todos are summarised, not listed.
|
|
157
170
|
record(
|
|
171
|
+
{componentsUsed: result.data.componentsUsed, todos: result.data.todos},
|
|
158
172
|
{
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
: '',
|
|
173
|
+
format: {
|
|
174
|
+
todos: (/** @type {string[]} */ todos) =>
|
|
175
|
+
`${todos.length} (search for "TODO(xle)")`,
|
|
176
|
+
},
|
|
164
177
|
},
|
|
165
|
-
{labels: {components: 'Components', todos: 'TODOs'}},
|
|
166
178
|
),
|
|
167
179
|
);
|
|
168
180
|
} else {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file `layout expand` and `layout check` document their input modes (the
|
|
5
|
+
* argument, `-` for stdin, --file) and where `layout expand` writes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {describe, it, expect} from 'vitest';
|
|
9
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
10
|
+
import {isFilePathArg} from '../../../foundation/fs/path-safety.mjs';
|
|
11
|
+
|
|
12
|
+
const SLOW = 30_000;
|
|
13
|
+
|
|
14
|
+
describe('layout argument behavior is documented', () => {
|
|
15
|
+
it('layout expand help covers stdin, --file precedence and the output path rule', async () => {
|
|
16
|
+
const {status, stdout} = await runCli(['layout', 'expand', '--help']);
|
|
17
|
+
expect(status).toBe(0);
|
|
18
|
+
expect(stdout).toMatch(/Pass - to read it from stdin/);
|
|
19
|
+
expect(stdout).toMatch(/instead of the argument/);
|
|
20
|
+
expect(stdout).toContain('<Name>.tsx');
|
|
21
|
+
expect(stdout).toMatch(/existing file there is replaced/);
|
|
22
|
+
const exts = [...(stdout.match(/ends in ([.\w, ]+ or \.\w+)/)?.[1] ?? '').matchAll(/\.\w+/g)];
|
|
23
|
+
expect(exts.length).toBeGreaterThan(0);
|
|
24
|
+
for (const [ext] of exts) expect(isFilePathArg(`src/Page${ext}`)).toBe(true);
|
|
25
|
+
}, SLOW);
|
|
26
|
+
|
|
27
|
+
it('layout check help covers stdin and --file precedence', async () => {
|
|
28
|
+
const {status, stdout} = await runCli(['layout', 'check', '--help']);
|
|
29
|
+
expect(status).toBe(0);
|
|
30
|
+
expect(stdout).toMatch(/Pass - to read it from stdin/);
|
|
31
|
+
expect(stdout).toMatch(/instead of the argument/);
|
|
32
|
+
}, SLOW);
|
|
33
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file `layout check -` reads the expression from stdin under the same 5 MB
|
|
5
|
+
* cap as --file, instead of buffering whatever the pipe delivers. Spawns the
|
|
6
|
+
* real bin, since the in-process harness has no stdin.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {describe, it, expect} from 'vitest';
|
|
10
|
+
import {spawnSync} from 'node:child_process';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import {fileURLToPath} from 'node:url';
|
|
13
|
+
|
|
14
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const BIN = path.resolve(HERE, '../bin/astryx.mjs');
|
|
16
|
+
// Run against the monorepo root so @astryxdesign/core is discoverable.
|
|
17
|
+
const REPO = path.resolve(HERE, '../../../..');
|
|
18
|
+
const SLOW = 60_000;
|
|
19
|
+
|
|
20
|
+
/** @param {string} input @param {string[]} [extra] */
|
|
21
|
+
function checkFromStdin(input, extra = []) {
|
|
22
|
+
return spawnSync(process.execPath, [BIN, 'layout', 'check', '-', ...extra], {
|
|
23
|
+
cwd: REPO,
|
|
24
|
+
input,
|
|
25
|
+
encoding: 'utf-8',
|
|
26
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('layout check - (stdin)', () => {
|
|
31
|
+
it('refuses more than 5 MB with ERR_INVALID_ARGUMENT, in both modes', () => {
|
|
32
|
+
// Valid once trimmed, so only the cap can reject it.
|
|
33
|
+
const big = ' '.repeat(5 * 1024 * 1024 + 1) + 'V';
|
|
34
|
+
const json = checkFromStdin(big, ['--json']);
|
|
35
|
+
expect(json.status).toBe(1);
|
|
36
|
+
expect(JSON.parse(json.stdout).code).toBe('ERR_INVALID_ARGUMENT');
|
|
37
|
+
const human = checkFromStdin(big);
|
|
38
|
+
expect(human.status).toBe(1);
|
|
39
|
+
expect(human.stderr + human.stdout).toMatch(/too large/);
|
|
40
|
+
}, SLOW);
|
|
41
|
+
|
|
42
|
+
it('still reads a normal expression', () => {
|
|
43
|
+
const r = checkFromStdin('V > B', ['--json']);
|
|
44
|
+
expect(r.status).toBe(0);
|
|
45
|
+
expect(JSON.parse(r.stdout).data.valid).toBe(true);
|
|
46
|
+
}, SLOW);
|
|
47
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file `layout expand` text output names its fields after the JSON keys, so
|
|
5
|
+
* the two views stay greppable against each other.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
12
|
+
|
|
13
|
+
const SLOW = 60_000;
|
|
14
|
+
|
|
15
|
+
describe('layout expand text fields mirror the JSON keys', () => {
|
|
16
|
+
let cwd;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
// Inside the workspace so @astryxdesign/core resolves.
|
|
19
|
+
cwd = fs.mkdtempSync(path.join(process.cwd(), '.xle-text-fields-'));
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => fs.rmSync(cwd, {recursive: true, force: true}));
|
|
22
|
+
|
|
23
|
+
it('labels every record field with a key of the layout.expand data', async () => {
|
|
24
|
+
const expr = 'V > B + {not-a-real-block}';
|
|
25
|
+
const json = await runCli(['layout', 'expand', expr, './a', '--loose', '--json'], cwd);
|
|
26
|
+
expect(json.status).toBe(0);
|
|
27
|
+
const {data} = JSON.parse(json.stdout);
|
|
28
|
+
expect(data.todos.length).toBeGreaterThan(0);
|
|
29
|
+
|
|
30
|
+
const human = await runCli(['layout', 'expand', expr, './b', '--loose'], cwd);
|
|
31
|
+
expect(human.status).toBe(0);
|
|
32
|
+
const fields = human.stdout
|
|
33
|
+
.split('\n')
|
|
34
|
+
.map(line => /^([A-Za-z]+):\s/.exec(line)?.[1])
|
|
35
|
+
.filter(Boolean);
|
|
36
|
+
expect(fields).toEqual(['componentsUsed', 'todos']);
|
|
37
|
+
for (const field of fields) expect(Object.keys(data)).toContain(field);
|
|
38
|
+
}, SLOW);
|
|
39
|
+
});
|
|
@@ -12,7 +12,7 @@ export const doc = {
|
|
|
12
12
|
type: 'command',
|
|
13
13
|
name: 'manifest',
|
|
14
14
|
displayName: 'astryx manifest',
|
|
15
|
-
namespace: 'cli',
|
|
15
|
+
namespace: 'cli/commands',
|
|
16
16
|
summary: 'Print the full CLI capability manifest (use with --json).',
|
|
17
17
|
description:
|
|
18
18
|
'Emits the complete CLI surface: every command with its arguments, options, ' +
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The CLI never asks a question, so no help text, manifest entry or
|
|
5
|
+
* error-code description may say a flag skips a prompt. Each flag's text states
|
|
6
|
+
* what happens without it instead, and the CLI does that.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import {fileURLToPath} from 'node:url';
|
|
14
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
15
|
+
import {doc as errorCodesDoc} from '../../../foundation/response/error-codes.doc.mjs';
|
|
16
|
+
import {doc as upgradeFn} from '../../../api/upgrade/upgrade.doc.mjs';
|
|
17
|
+
|
|
18
|
+
const CLI_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
|
|
19
|
+
const SLOW = 30_000;
|
|
20
|
+
|
|
21
|
+
/** @type {string} */
|
|
22
|
+
let tmpDir;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-no-prompt-'));
|
|
26
|
+
fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({name: 'consumer'}));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* One option's description from the manifest (subcommands are nested).
|
|
35
|
+
* @param {string} command @param {string} flag
|
|
36
|
+
*/
|
|
37
|
+
async function optionText(command, flag) {
|
|
38
|
+
const {stdout} = await runCli(['--json', 'manifest'], tmpDir);
|
|
39
|
+
/** @typedef {{name: string, options: Array<{flag: string, description: string}>, subcommands?: ManifestCommand[]}} ManifestCommand */
|
|
40
|
+
/** @param {ManifestCommand[]} list @returns {ManifestCommand | undefined} */
|
|
41
|
+
const find = list => {
|
|
42
|
+
for (const c of list) {
|
|
43
|
+
const hit = c.name === command ? c : find(c.subcommands ?? []);
|
|
44
|
+
if (hit) return hit;
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
};
|
|
48
|
+
const cmd = find(JSON.parse(stdout).data.commands);
|
|
49
|
+
return cmd?.options.find(o => o.flag.includes(flag))?.description ?? '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
describe('no help text describes a prompt', () => {
|
|
53
|
+
it('theme add --overwrite states the refusal, and a refused run writes nothing', async () => {
|
|
54
|
+
const help = await optionText('theme add', '--overwrite');
|
|
55
|
+
expect(help).not.toMatch(/prompt/i);
|
|
56
|
+
expect(help).toContain('ERR_FILE_EXISTS');
|
|
57
|
+
expect(help).toMatch(/nothing is written/);
|
|
58
|
+
|
|
59
|
+
const first = await runCli(['--json', 'theme', 'add', 'matcha'], tmpDir);
|
|
60
|
+
expect(first.status).toBe(0);
|
|
61
|
+
const {outputDir, files} = JSON.parse(first.stdout).data;
|
|
62
|
+
expect(files.length).toBeGreaterThan(1);
|
|
63
|
+
const dir = path.join(tmpDir, outputDir);
|
|
64
|
+
fs.writeFileSync(path.join(dir, files[0]), '// edited\n');
|
|
65
|
+
fs.rmSync(path.join(dir, files[1]));
|
|
66
|
+
|
|
67
|
+
const refused = await runCli(['--json', 'theme', 'add', 'matcha'], tmpDir);
|
|
68
|
+
expect(refused.status).toBe(1);
|
|
69
|
+
expect(JSON.parse(refused.stdout).code).toBe('ERR_FILE_EXISTS');
|
|
70
|
+
expect(fs.readFileSync(path.join(dir, files[0]), 'utf8')).toBe('// edited\n');
|
|
71
|
+
expect(fs.existsSync(path.join(dir, files[1]))).toBe(false);
|
|
72
|
+
}, SLOW);
|
|
73
|
+
|
|
74
|
+
it('upgrade --install-deps names the failure without it, in help and in the API doc', async () => {
|
|
75
|
+
const help = await optionText('upgrade', '--install-deps');
|
|
76
|
+
const param = upgradeFn.params?.find(p => p.name === 'options.installDeps')?.description ?? '';
|
|
77
|
+
for (const text of [help, param]) {
|
|
78
|
+
expect(text).not.toMatch(/prompt/i);
|
|
79
|
+
expect(text).toContain('ERR_DEP_MISSING');
|
|
80
|
+
}
|
|
81
|
+
}, SLOW);
|
|
82
|
+
|
|
83
|
+
it('ERR_FILE_EXISTS is described without an interactive mode, in the code set, its doc and the README table', () => {
|
|
84
|
+
const member = errorCodesDoc.members.find(m => m.value === 'ERR_FILE_EXISTS');
|
|
85
|
+
expect(member?.description).toBe('Refused to overwrite an existing file.');
|
|
86
|
+
|
|
87
|
+
const source = fs.readFileSync(path.join(CLI_ROOT, 'foundation/response/error-codes.mjs'), 'utf8');
|
|
88
|
+
expect(source).toMatch(/\/\*\* Refused to overwrite an existing file\. \*\/\s*ERR_FILE_EXISTS:/);
|
|
89
|
+
|
|
90
|
+
const readme = fs.readFileSync(path.join(CLI_ROOT, 'README.md'), 'utf8');
|
|
91
|
+
const row = readme.split('\n').find(line => line.startsWith('| `ERR_FILE_EXISTS`'));
|
|
92
|
+
expect(row).toMatch(/\| Refused to overwrite an existing file\.\s+\|$/);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -12,7 +12,7 @@ export const doc = {
|
|
|
12
12
|
type: 'command',
|
|
13
13
|
name: 'search',
|
|
14
14
|
displayName: 'astryx search',
|
|
15
|
-
namespace: 'cli',
|
|
15
|
+
namespace: 'cli/commands',
|
|
16
16
|
summary: 'Search components, hooks, docs, and templates in one ranked list',
|
|
17
17
|
description:
|
|
18
18
|
'Terminal front-end to search(): prints one ranked, greppable list across ' +
|
|
@@ -29,11 +29,11 @@ export const doc = {
|
|
|
29
29
|
{
|
|
30
30
|
flag: '--limit <n>',
|
|
31
31
|
param: 'options.limit',
|
|
32
|
-
description: 'Max number of results (default 20)',
|
|
32
|
+
description: 'Max number of results, a positive integer (default 20)',
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
flag: '--verbose',
|
|
36
|
-
description:
|
|
36
|
+
description: "Also print each result's score and match reason",
|
|
37
37
|
},
|
|
38
38
|
],
|
|
39
39
|
examples: [
|
|
@@ -45,7 +45,10 @@ export const doc = {
|
|
|
45
45
|
],
|
|
46
46
|
exitCodes: [
|
|
47
47
|
{code: 0, when: 'success (including zero matches)'},
|
|
48
|
-
{
|
|
48
|
+
{
|
|
49
|
+
code: 1,
|
|
50
|
+
when: 'invalid --type, a --limit that is not a positive integer, or @astryxdesign/core cannot be found',
|
|
51
|
+
},
|
|
49
52
|
],
|
|
50
53
|
related: ['component', 'hook', 'docs', 'template', 'build'],
|
|
51
54
|
};
|