@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,6 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
import {afterEach, beforeEach, describe, expect, it} from 'vitest';
|
|
4
|
+
import {execFileSync} from 'node:child_process';
|
|
4
5
|
import * as fs from 'node:fs';
|
|
5
6
|
import * as os from 'node:os';
|
|
6
7
|
import * as path from 'node:path';
|
|
@@ -8,75 +9,98 @@ import {
|
|
|
8
9
|
BUNDLED_THEME_PACKAGE,
|
|
9
10
|
discoverBundledThemes,
|
|
10
11
|
discoverIntegrationThemes,
|
|
11
|
-
|
|
12
|
+
discoverThemeDirectory,
|
|
12
13
|
} from './theme-discovery.mjs';
|
|
13
14
|
|
|
14
15
|
let tmpDir;
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
/** @param {Record<string, unknown>} doc */
|
|
18
|
+
function descriptorSource(doc) {
|
|
19
|
+
return `/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */\nexport default ${JSON.stringify(doc, null, 2)};\n`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {{slug?: string, stem?: string, extension?: string, source?: string,
|
|
24
|
+
* doc?: Record<string, unknown>, files?: Record<string, string>}} [options]
|
|
25
|
+
*/
|
|
26
|
+
function writeTheme({
|
|
27
|
+
slug = 'ocean',
|
|
28
|
+
stem = 'oceanTheme',
|
|
29
|
+
extension = '.ts',
|
|
30
|
+
source = `export const ${stem} = {};\n`,
|
|
31
|
+
doc = {},
|
|
32
|
+
files = {},
|
|
33
|
+
} = {}) {
|
|
34
|
+
const themeDir = path.join(tmpDir, slug);
|
|
35
|
+
fs.mkdirSync(themeDir, {recursive: true});
|
|
36
|
+
fs.writeFileSync(path.join(themeDir, `${stem}${extension}`), source);
|
|
27
37
|
fs.writeFileSync(
|
|
28
|
-
path.join(
|
|
29
|
-
|
|
38
|
+
path.join(themeDir, `${stem}.doc.mjs`),
|
|
39
|
+
descriptorSource({
|
|
40
|
+
type: 'theme',
|
|
41
|
+
name: slug,
|
|
42
|
+
displayName: 'Ocean',
|
|
43
|
+
description: 'Blue and calm.',
|
|
44
|
+
maintained: true,
|
|
45
|
+
...doc,
|
|
46
|
+
}),
|
|
30
47
|
);
|
|
48
|
+
for (const [file, contents] of Object.entries(files)) {
|
|
49
|
+
const target = path.join(themeDir, file);
|
|
50
|
+
fs.mkdirSync(path.dirname(target), {recursive: true});
|
|
51
|
+
fs.writeFileSync(target, contents);
|
|
52
|
+
}
|
|
53
|
+
return themeDir;
|
|
31
54
|
}
|
|
32
55
|
|
|
33
|
-
const ocean = {
|
|
34
|
-
slug: 'ocean',
|
|
35
|
-
displayName: 'Ocean',
|
|
36
|
-
description: 'Blue and calm.',
|
|
37
|
-
maintained: true,
|
|
38
|
-
entry: 'oceanTheme.ts',
|
|
39
|
-
exportName: 'oceanTheme',
|
|
40
|
-
files: ['oceanTheme.ts'],
|
|
41
|
-
};
|
|
42
|
-
|
|
43
56
|
beforeEach(() => {
|
|
44
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-theme-
|
|
57
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-theme-descriptor-'));
|
|
45
58
|
});
|
|
46
59
|
|
|
47
60
|
afterEach(() => {
|
|
48
61
|
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
49
62
|
});
|
|
50
63
|
|
|
51
|
-
describe('theme
|
|
52
|
-
it('reads
|
|
64
|
+
describe('theme descriptor discovery', () => {
|
|
65
|
+
it('reads bundled descriptors with package ownership', () => {
|
|
53
66
|
const themes = discoverBundledThemes();
|
|
54
67
|
expect(themes.length).toBeGreaterThan(0);
|
|
55
68
|
expect(themes.every(theme => theme.package === BUNDLED_THEME_PACKAGE)).toBe(
|
|
56
69
|
true,
|
|
57
70
|
);
|
|
58
71
|
expect(themes.every(theme => theme.bundled)).toBe(true);
|
|
72
|
+
expect(
|
|
73
|
+
themes.filter(theme => theme.maintained).map(theme => theme.slug),
|
|
74
|
+
).toEqual(['neutral']);
|
|
75
|
+
expect(themes.every(theme => theme.docPath.endsWith('.doc.mjs'))).toBe(
|
|
76
|
+
true,
|
|
77
|
+
);
|
|
59
78
|
});
|
|
60
79
|
|
|
61
|
-
it('
|
|
62
|
-
|
|
63
|
-
expect(
|
|
80
|
+
it('derives source entry and runtime export from the shared stem', () => {
|
|
81
|
+
writeTheme();
|
|
82
|
+
expect(discoverThemeDirectory(tmpDir, '@acme/themes')).toEqual([
|
|
64
83
|
expect.objectContaining({
|
|
65
|
-
|
|
84
|
+
slug: 'ocean',
|
|
85
|
+
displayName: 'Ocean',
|
|
86
|
+
description: 'Blue and calm.',
|
|
87
|
+
maintained: true,
|
|
88
|
+
entry: 'oceanTheme.ts',
|
|
89
|
+
exportName: 'oceanTheme',
|
|
90
|
+
files: ['oceanTheme.ts', 'oceanTheme.doc.mjs'],
|
|
66
91
|
package: '@acme/themes',
|
|
67
92
|
sourceDir: path.join(tmpDir, 'ocean'),
|
|
93
|
+
docPath: path.join(tmpDir, 'ocean', 'oceanTheme.doc.mjs'),
|
|
68
94
|
bundled: false,
|
|
69
95
|
}),
|
|
70
96
|
]);
|
|
71
97
|
});
|
|
72
98
|
|
|
73
|
-
it('parses
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
79
|
-
|
|
99
|
+
it('parses source without executing it', async () => {
|
|
100
|
+
writeTheme({
|
|
101
|
+
source:
|
|
102
|
+
"throw new Error('theme source executed');\nexport const oceanTheme = {};\n",
|
|
103
|
+
});
|
|
80
104
|
await expect(
|
|
81
105
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
82
106
|
).resolves.toEqual([
|
|
@@ -84,39 +108,50 @@ describe('theme catalog discovery', () => {
|
|
|
84
108
|
]);
|
|
85
109
|
});
|
|
86
110
|
|
|
87
|
-
it('rejects an
|
|
88
|
-
|
|
111
|
+
it('rejects an untyped descriptor', () => {
|
|
112
|
+
const themeDir = writeTheme();
|
|
89
113
|
fs.writeFileSync(
|
|
90
|
-
path.join(
|
|
91
|
-
|
|
114
|
+
path.join(themeDir, 'oceanTheme.doc.mjs'),
|
|
115
|
+
"export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: '', maintained: true};\n",
|
|
92
116
|
);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
96
|
-
).rejects.toThrow(
|
|
97
|
-
'Theme catalog for @acme/themes entry "oceanTheme.ts" does not export "oceanTheme".',
|
|
117
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
118
|
+
/must declare its public ThemeDoc type/u,
|
|
98
119
|
);
|
|
99
120
|
});
|
|
100
121
|
|
|
101
|
-
it('rejects a
|
|
102
|
-
|
|
122
|
+
it('rejects a descriptor module with executable statements', () => {
|
|
123
|
+
const themeDir = writeTheme();
|
|
103
124
|
fs.writeFileSync(
|
|
104
|
-
path.join(
|
|
105
|
-
|
|
125
|
+
path.join(themeDir, 'oceanTheme.doc.mjs'),
|
|
126
|
+
`throw new Error('descriptor executed');\n${descriptorSource({
|
|
127
|
+
type: 'theme',
|
|
128
|
+
name: 'ocean',
|
|
129
|
+
displayName: 'Ocean',
|
|
130
|
+
description: 'Blue and calm.',
|
|
131
|
+
maintained: true,
|
|
132
|
+
})}`,
|
|
133
|
+
);
|
|
134
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
135
|
+
/only its static default-exported ThemeDoc object/u,
|
|
106
136
|
);
|
|
137
|
+
});
|
|
107
138
|
|
|
139
|
+
it('rejects an entry that does not export its inferred runtime name', async () => {
|
|
140
|
+
writeTheme({source: 'export const anotherTheme = {};\n'});
|
|
108
141
|
await expect(
|
|
109
142
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
110
143
|
).rejects.toThrow(/does not export "oceanTheme"/u);
|
|
111
144
|
});
|
|
112
145
|
|
|
113
|
-
it('rejects
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
146
|
+
it('rejects a type-only export of its inferred runtime name', async () => {
|
|
147
|
+
writeTheme({source: 'export type oceanTheme = {};\n'});
|
|
148
|
+
await expect(
|
|
149
|
+
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
150
|
+
).rejects.toThrow(/does not export "oceanTheme"/u);
|
|
151
|
+
});
|
|
119
152
|
|
|
153
|
+
it('rejects an unbound source-less export specifier', async () => {
|
|
154
|
+
writeTheme({source: 'export {oceanTheme};\n'});
|
|
120
155
|
await expect(
|
|
121
156
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
122
157
|
).rejects.toThrow(
|
|
@@ -125,251 +160,610 @@ describe('theme catalog discovery', () => {
|
|
|
125
160
|
});
|
|
126
161
|
|
|
127
162
|
it('accepts a source-less export backed by a local runtime declaration', async () => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
163
|
+
writeTheme({source: 'const oceanTheme = {};\nexport {oceanTheme};\n'});
|
|
164
|
+
await expect(
|
|
165
|
+
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
166
|
+
).resolves.toHaveLength(1);
|
|
167
|
+
});
|
|
133
168
|
|
|
169
|
+
it('follows imported aliases and local re-exports without execution', async () => {
|
|
170
|
+
writeTheme({
|
|
171
|
+
source:
|
|
172
|
+
"import {theme as oceanTheme} from './tokens/theme';\nexport {oceanTheme};\n",
|
|
173
|
+
files: {
|
|
174
|
+
'tokens/theme.ts':
|
|
175
|
+
"throw new Error('nested source executed');\nexport const theme = {};\n",
|
|
176
|
+
},
|
|
177
|
+
});
|
|
134
178
|
await expect(
|
|
135
179
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
136
180
|
).resolves.toEqual([
|
|
137
|
-
expect.objectContaining({
|
|
181
|
+
expect.objectContaining({
|
|
182
|
+
files: ['oceanTheme.ts', 'oceanTheme.doc.mjs', 'tokens/theme.ts'],
|
|
183
|
+
}),
|
|
138
184
|
]);
|
|
139
185
|
});
|
|
140
186
|
|
|
141
|
-
it('
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
);
|
|
147
|
-
fs.writeFileSync(
|
|
148
|
-
path.join(tmpDir, 'ocean', 'theme.ts'),
|
|
149
|
-
'export const theme = {};\n',
|
|
150
|
-
);
|
|
151
|
-
|
|
187
|
+
it('follows a default re-export', async () => {
|
|
188
|
+
writeTheme({
|
|
189
|
+
source: "export {default as oceanTheme} from './theme';\n",
|
|
190
|
+
files: {'theme.ts': 'export default {};\n'},
|
|
191
|
+
});
|
|
152
192
|
await expect(
|
|
153
193
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
154
|
-
).resolves.
|
|
155
|
-
expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
|
|
156
|
-
]);
|
|
194
|
+
).resolves.toHaveLength(1);
|
|
157
195
|
});
|
|
158
196
|
|
|
159
|
-
it('
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
197
|
+
it('follows an export-all barrel', async () => {
|
|
198
|
+
writeTheme({
|
|
199
|
+
source: "export * from './theme';\n",
|
|
200
|
+
files: {'theme.ts': 'export const oceanTheme = {};\n'},
|
|
201
|
+
});
|
|
202
|
+
await expect(
|
|
203
|
+
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
204
|
+
).resolves.toHaveLength(1);
|
|
205
|
+
});
|
|
165
206
|
|
|
207
|
+
it('accepts a runtime binding imported from a package', async () => {
|
|
208
|
+
writeTheme({
|
|
209
|
+
source:
|
|
210
|
+
"import {defineTheme as oceanTheme} from '@astryxdesign/core/theme';\nexport {oceanTheme};\n",
|
|
211
|
+
});
|
|
166
212
|
await expect(
|
|
167
213
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
168
|
-
).resolves.
|
|
169
|
-
expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
|
|
170
|
-
]);
|
|
214
|
+
).resolves.toHaveLength(1);
|
|
171
215
|
});
|
|
172
216
|
|
|
173
|
-
it('
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
'
|
|
182
|
-
|
|
217
|
+
it('copies unreferenced nested authoring artifacts as part of the directory', () => {
|
|
218
|
+
writeTheme({
|
|
219
|
+
files: {
|
|
220
|
+
'tokens/ocean.palette.ts': 'export const palette = {};\n',
|
|
221
|
+
'receipts/palette.json': '{"version":1}\n',
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].files).toEqual([
|
|
225
|
+
'oceanTheme.ts',
|
|
226
|
+
'oceanTheme.doc.mjs',
|
|
227
|
+
'receipts/palette.json',
|
|
228
|
+
'tokens/ocean.palette.ts',
|
|
229
|
+
]);
|
|
230
|
+
});
|
|
183
231
|
|
|
232
|
+
it('rejects a theme source that imports its descriptor', async () => {
|
|
233
|
+
writeTheme({
|
|
234
|
+
source:
|
|
235
|
+
"import metadata from './oceanTheme.doc.mjs';\nvoid metadata;\nexport const oceanTheme = {};\n",
|
|
236
|
+
});
|
|
184
237
|
await expect(
|
|
185
238
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
186
|
-
).
|
|
187
|
-
expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
|
|
188
|
-
]);
|
|
239
|
+
).rejects.toThrow(/must not import its descriptor "oceanTheme\.doc\.mjs"/u);
|
|
189
240
|
});
|
|
190
241
|
|
|
191
|
-
it('
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
);
|
|
242
|
+
it('rejects a local import outside the theme directory', async () => {
|
|
243
|
+
writeTheme({
|
|
244
|
+
source:
|
|
245
|
+
"import {palette} from '../outside';\nexport const oceanTheme = {palette};\n",
|
|
246
|
+
});
|
|
197
247
|
fs.writeFileSync(
|
|
198
|
-
path.join(tmpDir, '
|
|
199
|
-
|
|
248
|
+
path.join(tmpDir, 'outside.ts'),
|
|
249
|
+
'export const palette = {};\n',
|
|
200
250
|
);
|
|
201
|
-
|
|
202
251
|
await expect(
|
|
203
252
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
204
|
-
).
|
|
205
|
-
expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
|
|
206
|
-
]);
|
|
253
|
+
).rejects.toThrow(/must resolve to a file inside the theme directory/u);
|
|
207
254
|
});
|
|
208
255
|
|
|
209
|
-
it('
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
|
|
215
|
-
"import {oceanPalette} from './tokens/ocean.palette';\nexport const oceanTheme = {oceanPalette};\n",
|
|
216
|
-
);
|
|
256
|
+
it('rejects a literal dynamic import outside the theme directory', async () => {
|
|
257
|
+
writeTheme({
|
|
258
|
+
extension: '.mjs',
|
|
259
|
+
source: "void import('../extra.mjs');\nexport const oceanTheme = {};\n",
|
|
260
|
+
});
|
|
217
261
|
fs.writeFileSync(
|
|
218
|
-
path.join(tmpDir, '
|
|
219
|
-
|
|
262
|
+
path.join(tmpDir, 'extra.mjs'),
|
|
263
|
+
'export const extra = {};\n',
|
|
220
264
|
);
|
|
221
|
-
|
|
222
265
|
await expect(
|
|
223
266
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
224
|
-
).
|
|
225
|
-
expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
|
|
226
|
-
]);
|
|
267
|
+
).rejects.toThrow(/must resolve to a file inside the theme directory/u);
|
|
227
268
|
});
|
|
228
269
|
|
|
229
|
-
it('rejects a
|
|
230
|
-
|
|
231
|
-
fs.mkdirSync(path.join(tmpDir, 'ocean', 'tokens'), {recursive: true});
|
|
270
|
+
it('rejects a local re-export outside the theme directory', async () => {
|
|
271
|
+
writeTheme({source: "export * from '../outside';\n"});
|
|
232
272
|
fs.writeFileSync(
|
|
233
|
-
path.join(tmpDir, '
|
|
234
|
-
|
|
235
|
-
);
|
|
236
|
-
fs.writeFileSync(
|
|
237
|
-
path.join(tmpDir, 'ocean', 'tokens', 'ocean.palette.ts'),
|
|
238
|
-
'export const oceanPalette = {};\n',
|
|
273
|
+
path.join(tmpDir, 'outside.ts'),
|
|
274
|
+
'export const oceanTheme = {};\n',
|
|
239
275
|
);
|
|
240
|
-
|
|
241
276
|
await expect(
|
|
242
277
|
discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
|
|
243
|
-
).rejects.toThrow(
|
|
244
|
-
|
|
278
|
+
).rejects.toThrow(/must resolve to a file inside the theme directory/u);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('rejects the obsolete central manifest even when descriptors exist', () => {
|
|
282
|
+
writeTheme();
|
|
283
|
+
fs.writeFileSync(path.join(tmpDir, 'manifest.json'), '{"version":1}\n');
|
|
284
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
285
|
+
/the theme catalog Astryx 0\.6 wrote.*astryx upgrade --from 0\.6\.3 --path \. --apply/u,
|
|
245
286
|
);
|
|
246
287
|
});
|
|
247
288
|
|
|
248
|
-
it('rejects a
|
|
249
|
-
writeCatalog([ocean]);
|
|
289
|
+
it('rejects a descriptor placed at the themes root', () => {
|
|
250
290
|
fs.writeFileSync(
|
|
251
|
-
path.join(tmpDir, '
|
|
252
|
-
|
|
291
|
+
path.join(tmpDir, 'oceanTheme.doc.mjs'),
|
|
292
|
+
descriptorSource({
|
|
293
|
+
type: 'theme',
|
|
294
|
+
name: 'ocean',
|
|
295
|
+
displayName: 'Ocean',
|
|
296
|
+
description: '',
|
|
297
|
+
maintained: true,
|
|
298
|
+
}),
|
|
253
299
|
);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
'export const oceanPalette = {};\n',
|
|
300
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
301
|
+
/must be inside a lower-kebab theme directory/u,
|
|
257
302
|
);
|
|
303
|
+
});
|
|
258
304
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
305
|
+
it('rejects a missing descriptor', () => {
|
|
306
|
+
const dir = path.join(tmpDir, 'ocean');
|
|
307
|
+
fs.mkdirSync(dir);
|
|
308
|
+
fs.writeFileSync(
|
|
309
|
+
path.join(dir, 'oceanTheme.ts'),
|
|
310
|
+
'export const oceanTheme = {};\n',
|
|
311
|
+
);
|
|
312
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
313
|
+
'Theme "ocean" for @acme/themes must contain exactly one same-stem .doc.mjs descriptor; found 0 beside "oceanTheme.ts".',
|
|
263
314
|
);
|
|
264
315
|
});
|
|
265
316
|
|
|
266
|
-
it('rejects
|
|
267
|
-
const
|
|
268
|
-
...ocean,
|
|
269
|
-
entry: 'oceanTheme.mjs',
|
|
270
|
-
files: ['oceanTheme.mjs'],
|
|
271
|
-
};
|
|
272
|
-
writeCatalog([mjsTheme]);
|
|
317
|
+
it('rejects more than one descriptor', () => {
|
|
318
|
+
const dir = writeTheme();
|
|
273
319
|
fs.writeFileSync(
|
|
274
|
-
path.join(
|
|
275
|
-
|
|
320
|
+
path.join(dir, 'other.doc.mjs'),
|
|
321
|
+
descriptorSource({
|
|
322
|
+
type: 'theme',
|
|
323
|
+
name: 'ocean',
|
|
324
|
+
displayName: 'Other',
|
|
325
|
+
description: '',
|
|
326
|
+
maintained: false,
|
|
327
|
+
}),
|
|
276
328
|
);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
'export const extra = {};\n',
|
|
329
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
330
|
+
'Theme "ocean" for @acme/themes must contain exactly one same-stem .doc.mjs descriptor; found 2: "oceanTheme.doc.mjs", "other.doc.mjs".',
|
|
280
331
|
);
|
|
332
|
+
});
|
|
281
333
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
334
|
+
it('rejects missing and ambiguous same-stem source files', () => {
|
|
335
|
+
const dir = writeTheme();
|
|
336
|
+
fs.rmSync(path.join(dir, 'oceanTheme.ts'));
|
|
337
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
338
|
+
/exactly one same-stem source.*found 0/u,
|
|
286
339
|
);
|
|
287
|
-
});
|
|
288
340
|
|
|
289
|
-
it('rejects a re-export outside the theme directory', async () => {
|
|
290
|
-
writeCatalog([ocean]);
|
|
291
341
|
fs.writeFileSync(
|
|
292
|
-
path.join(
|
|
293
|
-
|
|
342
|
+
path.join(dir, 'oceanTheme.ts'),
|
|
343
|
+
'export const oceanTheme = {};\n',
|
|
294
344
|
);
|
|
295
345
|
fs.writeFileSync(
|
|
296
|
-
path.join(
|
|
346
|
+
path.join(dir, 'oceanTheme.mjs'),
|
|
297
347
|
'export const oceanTheme = {};\n',
|
|
298
348
|
);
|
|
349
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
350
|
+
/exactly one same-stem source.*found 2/u,
|
|
351
|
+
);
|
|
352
|
+
});
|
|
299
353
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
).
|
|
303
|
-
|
|
354
|
+
it('rejects descriptor identity that differs from its directory', () => {
|
|
355
|
+
writeTheme({doc: {name: 'sea'}});
|
|
356
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
357
|
+
'Theme descriptor oceanTheme.doc.mjs for @acme/themes names "sea" but its directory is "ocean".',
|
|
304
358
|
);
|
|
305
359
|
});
|
|
306
360
|
|
|
307
|
-
it('rejects
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
"export * from './theme';\n",
|
|
361
|
+
it('rejects malformed descriptor fields and unknown catalog-era fields', () => {
|
|
362
|
+
writeTheme({doc: {maintained: 'yes'}});
|
|
363
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
364
|
+
/maintained/u,
|
|
312
365
|
);
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
366
|
+
|
|
367
|
+
fs.rmSync(path.join(tmpDir, 'ocean'), {recursive: true});
|
|
368
|
+
writeTheme({doc: {entry: 'oceanTheme.ts'}});
|
|
369
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
370
|
+
/unrecognized key|entry/iu,
|
|
371
|
+
);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('rejects invalid theme directory and source stem names', () => {
|
|
375
|
+
writeTheme({slug: 'Ocean'});
|
|
376
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
377
|
+
/invalid directory/u,
|
|
316
378
|
);
|
|
317
379
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
).
|
|
321
|
-
/
|
|
380
|
+
fs.rmSync(path.join(tmpDir, 'Ocean'), {recursive: true});
|
|
381
|
+
writeTheme({stem: 'ocean-theme'});
|
|
382
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
383
|
+
/not a valid runtime export name/u,
|
|
322
384
|
);
|
|
323
385
|
});
|
|
324
386
|
|
|
325
|
-
it('rejects
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
387
|
+
it('rejects symlinks inside the copy boundary', () => {
|
|
388
|
+
const dir = writeTheme();
|
|
389
|
+
const outside = path.join(tmpDir, 'outside.json');
|
|
390
|
+
fs.writeFileSync(outside, '{}\n');
|
|
391
|
+
fs.symlinkSync(outside, path.join(dir, 'outside.json'));
|
|
392
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
393
|
+
'Theme "ocean" for @acme/themes contains symlink "outside.json"; theme files must be regular files inside the theme directory.',
|
|
329
394
|
);
|
|
330
395
|
});
|
|
396
|
+
});
|
|
331
397
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
398
|
+
const TYPE = "/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */";
|
|
399
|
+
const BODY =
|
|
400
|
+
"{type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Blue and calm.', maintained: true}";
|
|
401
|
+
|
|
402
|
+
/** @param {string} source the whole descriptor file */
|
|
403
|
+
function writeDescriptor(source) {
|
|
404
|
+
const dir = writeTheme();
|
|
405
|
+
fs.writeFileSync(path.join(dir, 'oceanTheme.doc.mjs'), source);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
describe('theme descriptor type annotation', () => {
|
|
409
|
+
it.each([
|
|
410
|
+
['the annotation on the export', `${TYPE}\nexport default ${BODY};\n`],
|
|
411
|
+
[
|
|
412
|
+
'a header comment above the annotation',
|
|
413
|
+
`// Copyright (c) Meta Platforms, Inc. and affiliates.\n\n${TYPE}\nexport default ${BODY};\n`,
|
|
414
|
+
],
|
|
415
|
+
[
|
|
416
|
+
'a multi-line JSDoc block',
|
|
417
|
+
`/**\n * Ocean.\n *\n * @type {import("@astryxdesign/cli/authoring").ThemeDoc}\n */\nexport default ${BODY};\n`,
|
|
418
|
+
],
|
|
419
|
+
[
|
|
420
|
+
'a typedef alias',
|
|
421
|
+
`/** @typedef {import('@astryxdesign/cli/authoring').ThemeDoc} ThemeDoc */\n\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
|
|
422
|
+
],
|
|
423
|
+
[
|
|
424
|
+
'a typedef alias declared after the export',
|
|
425
|
+
`/** @type {Doc} */\nexport default ${BODY};\n/** @typedef {import('@astryxdesign/cli/authoring').ThemeDoc} Doc */\n`,
|
|
426
|
+
],
|
|
427
|
+
[
|
|
428
|
+
'an @import of the type',
|
|
429
|
+
`/** @import {ThemeDoc} from '@astryxdesign/cli/authoring' */\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
|
|
430
|
+
],
|
|
431
|
+
[
|
|
432
|
+
'a renamed @import',
|
|
433
|
+
`/** @import {ComponentDoc, ThemeDoc as Doc} from '@astryxdesign/cli/authoring' */\n/** @type {Doc} */\nexport default ${BODY};\n`,
|
|
434
|
+
],
|
|
435
|
+
[
|
|
436
|
+
'a namespace @import',
|
|
437
|
+
`/** @import * as authoring from '@astryxdesign/cli/authoring' */\n/** @type {authoring.ThemeDoc} */\nexport default ${BODY};\n`,
|
|
438
|
+
],
|
|
439
|
+
['a JSDoc cast of the object', `export default ${TYPE} (${BODY});\n`],
|
|
440
|
+
[
|
|
441
|
+
'a JSDoc cast inside outer parentheses',
|
|
442
|
+
`export default (${TYPE} (${BODY}));\n`,
|
|
443
|
+
],
|
|
444
|
+
[
|
|
445
|
+
'a @satisfies cast',
|
|
446
|
+
`export default ${TYPE.replace('@type', '@satisfies')} (${BODY});\n`,
|
|
447
|
+
],
|
|
448
|
+
...['!T', '?T', 'T=', '(T)', 'T | null', 'undefined | T', 'T & {}'].map(
|
|
449
|
+
form => [
|
|
450
|
+
`the type written {${form}}`,
|
|
451
|
+
`/** @type {${form.replace('T', "import('@astryxdesign/cli/authoring').ThemeDoc")}} */\nexport default ${BODY};\n`,
|
|
452
|
+
],
|
|
453
|
+
),
|
|
454
|
+
[
|
|
455
|
+
'an @import with a type modifier',
|
|
456
|
+
`/** @import {type ThemeDoc} from '@astryxdesign/cli/authoring' */\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
|
|
457
|
+
],
|
|
458
|
+
[
|
|
459
|
+
'a chain of typedef aliases',
|
|
460
|
+
`/** @typedef {import('@astryxdesign/cli/authoring').ThemeDoc} A */\n/** @typedef {A} B */\n/** @type {B} */\nexport default ${BODY};\n`,
|
|
461
|
+
],
|
|
462
|
+
])('accepts %s', (_, source) => {
|
|
463
|
+
writeDescriptor(source);
|
|
464
|
+
expect(discoverThemeDirectory(tmpDir, '@acme/themes')).toHaveLength(1);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it.each([
|
|
468
|
+
['a line comment', `// ${TYPE.slice(4, -3)}\nexport default ${BODY};\n`],
|
|
469
|
+
[
|
|
470
|
+
'a block comment that is not JSDoc',
|
|
471
|
+
`/* ${TYPE.slice(4, -3)} */\nexport default ${BODY};\n`,
|
|
472
|
+
],
|
|
473
|
+
['an annotation after the export', `export default ${BODY};\n${TYPE}\n`],
|
|
474
|
+
[
|
|
475
|
+
'an annotation inside a string value',
|
|
476
|
+
`export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: "${TYPE.slice(4, -3)}", maintained: true};\n`,
|
|
477
|
+
],
|
|
478
|
+
[
|
|
479
|
+
'an annotation on a property',
|
|
480
|
+
`export default {\n ${TYPE}\n type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Blue.', maintained: true};\n`,
|
|
481
|
+
],
|
|
482
|
+
[
|
|
483
|
+
'an unparenthesized inline annotation',
|
|
484
|
+
`export default ${TYPE} ${BODY};\n`,
|
|
485
|
+
],
|
|
486
|
+
[
|
|
487
|
+
'an annotation inside the parentheses',
|
|
488
|
+
`export default (${TYPE} ${BODY});\n`,
|
|
489
|
+
],
|
|
490
|
+
[
|
|
491
|
+
'a later JSDoc between the annotation and the export',
|
|
492
|
+
`${TYPE}\n/** Ocean. */\nexport default ${BODY};\n`,
|
|
493
|
+
],
|
|
494
|
+
[
|
|
495
|
+
'a typedef written as a line comment',
|
|
496
|
+
`// @typedef {import('@astryxdesign/cli/authoring').ThemeDoc} ThemeDoc\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
|
|
497
|
+
],
|
|
498
|
+
[
|
|
499
|
+
'an alias of another public type',
|
|
500
|
+
`/** @typedef {import('@astryxdesign/cli/authoring').ComponentDoc} ThemeDoc */\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
|
|
501
|
+
],
|
|
502
|
+
[
|
|
503
|
+
'a ThemeDoc from another module',
|
|
504
|
+
`/** @type {import('@astryxdesign/core').ThemeDoc} */\nexport default ${BODY};\n`,
|
|
505
|
+
],
|
|
506
|
+
[
|
|
507
|
+
'a type in a code span before the real @type {object}',
|
|
508
|
+
`/** Not \`${TYPE.slice(4, -3)}\` here. @type {object} */\nexport default ${BODY};\n`,
|
|
509
|
+
],
|
|
510
|
+
[
|
|
511
|
+
'a typedef in a code span',
|
|
512
|
+
`/** Declare \`@typedef {import('@astryxdesign/cli/authoring').ThemeDoc} TD\` first. */\n/** @type {TD} */\nexport default ${BODY};\n`,
|
|
513
|
+
],
|
|
514
|
+
[
|
|
515
|
+
'a type in a code span of a tag',
|
|
516
|
+
`/**\n * @see \` ${TYPE.slice(4, -3)}\` here\n */\nexport default ${BODY};\n`,
|
|
517
|
+
],
|
|
518
|
+
[
|
|
519
|
+
'@import type {...}, which is not @import syntax',
|
|
520
|
+
`/** @import type {ThemeDoc} from '@astryxdesign/cli/authoring' */\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
|
|
521
|
+
],
|
|
522
|
+
[
|
|
523
|
+
'@satisfies on the export statement',
|
|
524
|
+
`${TYPE.replace('@type', '@satisfies')}\nexport default ${BODY};\n`,
|
|
525
|
+
],
|
|
526
|
+
[
|
|
527
|
+
'an annotation before default, not before the parenthesis',
|
|
528
|
+
`export ${TYPE} default (${BODY});\n`,
|
|
529
|
+
],
|
|
530
|
+
[
|
|
531
|
+
'a union with another type',
|
|
532
|
+
`/** @type {import('@astryxdesign/cli/authoring').ThemeDoc | string} */\nexport default ${BODY};\n`,
|
|
533
|
+
],
|
|
534
|
+
])('rejects %s', (_, source) => {
|
|
535
|
+
writeDescriptor(source);
|
|
536
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
537
|
+
'Theme descriptor oceanTheme.doc.mjs for @acme/themes must declare its public ThemeDoc type from @astryxdesign/cli/authoring.',
|
|
538
|
+
);
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
describe('theme descriptor values', () => {
|
|
543
|
+
it.each([
|
|
544
|
+
['displayName', {displayName: ' '}],
|
|
545
|
+
['name', {name: ' '}],
|
|
546
|
+
])('rejects a blank %s', (field, doc) => {
|
|
547
|
+
writeTheme({doc});
|
|
548
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
549
|
+
`Theme descriptor oceanTheme.doc.mjs for @acme/themes is invalid: ${field}: ${field} must not be blank`,
|
|
550
|
+
);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it.each(['', ' '])('accepts a blank description (%j)', description => {
|
|
554
|
+
writeTheme({doc: {description}});
|
|
555
|
+
expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].description).toBe(
|
|
556
|
+
description,
|
|
557
|
+
);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it.each(['__proto__', "'__proto__'", 'extra'])(
|
|
561
|
+
'rejects the unknown key %s',
|
|
562
|
+
key => {
|
|
563
|
+
writeDescriptor(
|
|
564
|
+
`${TYPE}\nexport default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Blue.', maintained: true, ${key}: 'x'};\n`,
|
|
565
|
+
);
|
|
566
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
567
|
+
`Theme descriptor oceanTheme.doc.mjs for @acme/themes is invalid: (root): Unrecognized key: "${key.replaceAll("'", '')}"`,
|
|
568
|
+
);
|
|
569
|
+
},
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
it('rejects a BigInt where a string belongs', () => {
|
|
573
|
+
writeDescriptor(
|
|
574
|
+
`${TYPE}\nexport default {type: 'theme', name: 'ocean', displayName: 10n, description: 'Blue.', maintained: true};\n`,
|
|
575
|
+
);
|
|
576
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
577
|
+
/must use static string and boolean values/u,
|
|
337
578
|
);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it('reuses a read while the file keeps its size and mtime', () => {
|
|
582
|
+
const dir = writeTheme();
|
|
583
|
+
const file = path.join(dir, 'oceanTheme.doc.mjs');
|
|
584
|
+
const pinned = new Date('2020-01-01T00:00:00Z');
|
|
585
|
+
fs.utimesSync(file, pinned, pinned);
|
|
586
|
+
expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].displayName).toBe(
|
|
587
|
+
'Ocean',
|
|
588
|
+
);
|
|
589
|
+
|
|
338
590
|
fs.writeFileSync(
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
entry: '../outside.ts',
|
|
346
|
-
files: ['../outside.ts'],
|
|
347
|
-
},
|
|
348
|
-
],
|
|
349
|
-
}),
|
|
591
|
+
file,
|
|
592
|
+
fs.readFileSync(file, 'utf-8').replace('"Ocean"', '"Coral"'),
|
|
593
|
+
);
|
|
594
|
+
fs.utimesSync(file, pinned, pinned);
|
|
595
|
+
expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].displayName).toBe(
|
|
596
|
+
'Ocean',
|
|
350
597
|
);
|
|
351
|
-
|
|
352
|
-
|
|
598
|
+
|
|
599
|
+
const later = new Date('2020-01-01T00:00:01Z');
|
|
600
|
+
fs.utimesSync(file, later, later);
|
|
601
|
+
expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].displayName).toBe(
|
|
602
|
+
'Coral',
|
|
353
603
|
);
|
|
354
604
|
});
|
|
605
|
+
});
|
|
355
606
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
607
|
+
describe('theme folder messages', () => {
|
|
608
|
+
it('names the package and file of a symlinked descriptor', () => {
|
|
609
|
+
const dir = path.join(tmpDir, 'ocean');
|
|
610
|
+
fs.mkdirSync(dir);
|
|
611
|
+
fs.writeFileSync(
|
|
612
|
+
path.join(dir, 'oceanTheme.ts'),
|
|
613
|
+
'export const oceanTheme = {};\n',
|
|
359
614
|
);
|
|
615
|
+
const elsewhere = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-linked-'));
|
|
616
|
+
try {
|
|
617
|
+
const target = path.join(elsewhere, 'oceanTheme.doc.mjs');
|
|
618
|
+
fs.writeFileSync(target, `${TYPE}\nexport default ${BODY};\n`);
|
|
619
|
+
fs.symlinkSync(target, path.join(dir, 'oceanTheme.doc.mjs'));
|
|
620
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
621
|
+
'Theme "ocean" for @acme/themes contains symlink "oceanTheme.doc.mjs"; theme files must be regular files inside the theme directory.',
|
|
622
|
+
);
|
|
623
|
+
} finally {
|
|
624
|
+
fs.rmSync(elsewhere, {recursive: true, force: true});
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
it('names the package and both files of a nested second descriptor', () => {
|
|
629
|
+
writeTheme({
|
|
630
|
+
files: {'extra/otherTheme.doc.mjs': `${TYPE}\nexport default ${BODY};\n`},
|
|
631
|
+
});
|
|
632
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
633
|
+
'Theme "ocean" for @acme/themes contains more than one .doc.mjs descriptor: "oceanTheme.doc.mjs" and "extra/otherTheme.doc.mjs".',
|
|
634
|
+
);
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
const UNPUBLISHED = [
|
|
639
|
+
'.DS_Store',
|
|
640
|
+
'._oceanTheme.ts',
|
|
641
|
+
'.gitignore',
|
|
642
|
+
'.npmignore',
|
|
643
|
+
'.npmrc',
|
|
644
|
+
'oceanTheme.ts.orig',
|
|
645
|
+
'npm-debug.log',
|
|
646
|
+
'palette/.DS_Store',
|
|
647
|
+
'palette/npm-debug.log',
|
|
648
|
+
'.git/HEAD',
|
|
649
|
+
'CVS/Entries',
|
|
650
|
+
'node_modules/dep/index.js',
|
|
651
|
+
];
|
|
652
|
+
|
|
653
|
+
describe('files a theme leaves out', () => {
|
|
654
|
+
it('leaves out dot entries and files npm never publishes, at any depth', () => {
|
|
655
|
+
const dir = writeTheme({files: {'palette/tokens.ts': 'export {};\n'}});
|
|
656
|
+
for (const file of UNPUBLISHED) {
|
|
657
|
+
fs.mkdirSync(path.dirname(path.join(dir, file)), {recursive: true});
|
|
658
|
+
fs.writeFileSync(path.join(dir, file), 'x\n');
|
|
659
|
+
}
|
|
660
|
+
fs.symlinkSync(path.join(dir, 'palette'), path.join(dir, '.linked'));
|
|
661
|
+
fs.mkdirSync(path.join(tmpDir, 'node_modules', 'dep'), {recursive: true});
|
|
662
|
+
fs.writeFileSync(path.join(tmpDir, 'npm-debug.log'), 'x\n');
|
|
663
|
+
expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].files).toEqual([
|
|
664
|
+
'oceanTheme.ts',
|
|
665
|
+
'oceanTheme.doc.mjs',
|
|
666
|
+
'palette/tokens.ts',
|
|
667
|
+
]);
|
|
668
|
+
});
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
describe('folders under a theme root that are not themes', () => {
|
|
672
|
+
it('skips dot-folders and folders with neither a descriptor nor a theme source', () => {
|
|
673
|
+
writeTheme();
|
|
674
|
+
const stray = {
|
|
675
|
+
'shared/palette.ts': 'export const blue = "#00f";\n',
|
|
676
|
+
'.cache/state.json': '{}\n',
|
|
677
|
+
'.cache/stateTheme.ts': 'export const stateTheme = {};\n',
|
|
678
|
+
'__tests__/oceanTheme.test.ts': 'export {};\n',
|
|
679
|
+
'Shared_Helpers/colors.ts': 'export const red = "#f00";\n',
|
|
680
|
+
};
|
|
681
|
+
for (const [file, contents] of Object.entries(stray)) {
|
|
682
|
+
fs.mkdirSync(path.dirname(path.join(tmpDir, file)), {recursive: true});
|
|
683
|
+
fs.writeFileSync(path.join(tmpDir, file), contents);
|
|
684
|
+
}
|
|
685
|
+
fs.mkdirSync(path.join(tmpDir, 'empty'));
|
|
686
|
+
fs.symlinkSync(path.join(tmpDir, 'shared'), path.join(tmpDir, '.linked'));
|
|
687
|
+
expect(
|
|
688
|
+
discoverThemeDirectory(tmpDir, '@acme/themes').map(theme => theme.slug),
|
|
689
|
+
).toEqual(['ocean']);
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
it('still fails a folder with a theme source and no descriptor', () => {
|
|
693
|
+
writeTheme();
|
|
694
|
+
fs.mkdirSync(path.join(tmpDir, 'sand'));
|
|
360
695
|
fs.writeFileSync(
|
|
361
|
-
path.join(tmpDir, '
|
|
362
|
-
|
|
696
|
+
path.join(tmpDir, 'sand', 'sandTheme.ts'),
|
|
697
|
+
'export const sandTheme = {};\n',
|
|
363
698
|
);
|
|
364
|
-
expect(() =>
|
|
365
|
-
/
|
|
699
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
700
|
+
'Theme "sand" for @acme/themes must contain exactly one same-stem .doc.mjs descriptor; found 0 beside "sandTheme.ts".',
|
|
701
|
+
);
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
it('still fails a folder whose descriptor sits in a subfolder', () => {
|
|
705
|
+
writeTheme({slug: 'reef', stem: 'reefTheme', doc: {name: 'reef'}});
|
|
706
|
+
fs.mkdirSync(path.join(tmpDir, 'reef', 'src'));
|
|
707
|
+
for (const file of ['reefTheme.ts', 'reefTheme.doc.mjs']) {
|
|
708
|
+
fs.renameSync(
|
|
709
|
+
path.join(tmpDir, 'reef', file),
|
|
710
|
+
path.join(tmpDir, 'reef', 'src', file),
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
|
|
714
|
+
'Theme "reef" for @acme/themes must contain exactly one same-stem .doc.mjs descriptor; found 0; "src/reefTheme.doc.mjs" is in a subfolder.',
|
|
366
715
|
);
|
|
367
716
|
});
|
|
717
|
+
});
|
|
368
718
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
719
|
+
describe('bundled theme files', () => {
|
|
720
|
+
it('copies what the bundle has always copied, entry first, without its descriptor', () => {
|
|
721
|
+
const themes = discoverBundledThemes();
|
|
722
|
+
expect(themes.find(theme => theme.slug === 'neutral')?.files).toEqual([
|
|
723
|
+
'neutralTheme.ts',
|
|
724
|
+
'icons.tsx',
|
|
725
|
+
'neutralPalettes.ts',
|
|
726
|
+
'neutralPalettes.generated.ts',
|
|
727
|
+
'neutralPaletteRefs.generated.ts',
|
|
728
|
+
'neutralPalettes.generated.receipt.json',
|
|
729
|
+
'palette.config.json',
|
|
730
|
+
]);
|
|
731
|
+
for (const theme of themes) {
|
|
732
|
+
expect(theme.files[0]).toBe(theme.entry);
|
|
733
|
+
expect(theme.files.some(file => file.endsWith('.doc.mjs'))).toBe(false);
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
it('passes the full source check it skips at runtime', () => {
|
|
738
|
+
const bundled = discoverBundledThemes();
|
|
739
|
+
const checked = discoverThemeDirectory(
|
|
740
|
+
path.dirname(bundled[0].sourceDir),
|
|
741
|
+
BUNDLED_THEME_PACKAGE,
|
|
742
|
+
);
|
|
743
|
+
expect(checked.map(theme => theme.slug)).toEqual(
|
|
744
|
+
bundled.map(theme => theme.slug),
|
|
373
745
|
);
|
|
374
746
|
});
|
|
747
|
+
|
|
748
|
+
it('loads no parser on import and only the descriptor parser for bundled themes', () => {
|
|
749
|
+
const script = `
|
|
750
|
+
import {createRequire} from 'node:module';
|
|
751
|
+
const cache = createRequire(import.meta.url).cache;
|
|
752
|
+
const loaded = name => Object.keys(cache).some(file => file.includes('/node_modules/' + name + '/'));
|
|
753
|
+
const state = () => ({babel: loaded('@babel/parser'), jscodeshift: loaded('jscodeshift')});
|
|
754
|
+
const discovery = await import(${JSON.stringify(new URL('./theme-discovery.mjs', import.meta.url).href)});
|
|
755
|
+
const imported = state();
|
|
756
|
+
discovery.discoverBundledThemes();
|
|
757
|
+
console.log(JSON.stringify({imported, bundled: state()}));
|
|
758
|
+
`;
|
|
759
|
+
const output = execFileSync(
|
|
760
|
+
process.execPath,
|
|
761
|
+
['--input-type=module', '-e', script],
|
|
762
|
+
{encoding: 'utf-8'},
|
|
763
|
+
);
|
|
764
|
+
expect(JSON.parse(output)).toEqual({
|
|
765
|
+
imported: {babel: false, jscodeshift: false},
|
|
766
|
+
bundled: {babel: true, jscodeshift: false},
|
|
767
|
+
});
|
|
768
|
+
});
|
|
375
769
|
});
|