@astryxdesign/cli 0.6.3-canary.98a2e4e → 0.6.3-canary.9c4d44d
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/README.md +117 -79
- 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 +268 -47
- package/api/docs/_adapter.mjs +970 -149
- package/api/docs/compiled-topics.test.mjs +78 -0
- package/api/docs/detail/detail.d.mts +0 -15
- package/api/docs/detail/detail.mjs +22 -78
- package/api/docs/detail/section/section.mjs +39 -24
- package/api/docs/detail/section/section.test.mjs +19 -9
- package/api/docs/docs.d.mts +5 -3
- package/api/docs/docs.doc.mjs +39 -17
- package/api/docs/docs.mjs +44 -8
- package/api/docs/docs.test.mjs +158 -4
- package/api/docs/docs.type.d.mts +185 -6
- package/api/docs/docs.type.mjs +127 -13
- package/api/docs/index/index.mjs +15 -6
- package/api/docs/index/index.test.mjs +1 -1
- package/api/docs/integration-tree.test.mjs +555 -0
- package/api/docs/integrationDocs.test.mjs +14 -14
- 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 +54 -4
- package/api/doctor/doctor.doc.mjs +1 -0
- package/api/doctor/doctor.mjs +332 -21
- package/api/doctor/doctor.test.mjs +420 -7
- 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 +1 -1
- 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 +2 -0
- 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 +61 -10
- 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 +14 -2
- 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.doc.mjs +30 -8
- package/api/template/template.mjs +45 -8
- package/api/template/template.type.d.mts +11 -13
- 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 +124 -73
- package/api/upgrade/list/list.mjs +2 -1
- package/api/upgrade/list/list.test.mjs +73 -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 +8 -2
- package/api/upgrade/upgrade.type.d.mts +42 -4
- package/api/upgrade/upgrade.type.mjs +26 -10
- 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/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/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
- package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
- package/assets/codemods/transforms/next/index.mjs +19 -1
- package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
- package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -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/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} +95 -39
- 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/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 +7 -7
- 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 +240 -128
- package/authoring/doctypes/_schema.mjs +198 -16
- package/authoring/doctypes/base/graph-fields.doc.mjs +15 -6
- package/authoring/doctypes/base/type.ts +9 -4
- 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 +4 -4
- package/authoring/doctypes/component/component.doc.mjs +5 -2
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +3 -3
- 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 +2 -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 +4 -3
- 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 +3 -3
- package/authoring/doctypes/legacy.d.mts +6 -6
- package/authoring/doctypes/legacy.mjs +3 -3
- package/authoring/doctypes/load-contract.test.mjs +233 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +9 -9
- package/authoring/doctypes/namespace/parse.d.mts +2 -2
- package/authoring/doctypes/namespace/parse.mjs +1 -1
- package/authoring/doctypes/namespace/parse.test.mjs +23 -25
- package/authoring/doctypes/namespace/type.ts +6 -3
- package/authoring/doctypes/parse.d.mts +22 -20
- package/authoring/doctypes/parse.mjs +19 -14
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +1 -1
- package/authoring/doctypes/reference/reference.doc.mjs +39 -6
- package/authoring/doctypes/reference/type.ts +31 -14
- 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 +3 -4
- package/authoring/doctypes/template/parse.d.mts +94 -1
- package/authoring/doctypes/template/parse.mjs +37 -1
- package/authoring/doctypes/template/parse.test.mjs +18 -0
- package/authoring/doctypes/template/template.doc.mjs +13 -3
- package/authoring/doctypes/template/type.ts +12 -1
- 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 -11
- 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 +9 -9
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/identity/identity.doc.mjs +3 -2
- package/authoring/identity/type.ts +10 -10
- package/authoring/index.d.mts +2 -0
- package/authoring/index.d.ts +32 -19
- package/authoring/index.mjs +3 -1
- package/authoring/integration/integration.doc.mjs +2 -2
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/schema.d.mts +4 -4
- package/authoring/integration/schema.mjs +3 -3
- package/authoring/integration/type.ts +5 -11
- 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 +21 -9
- package/clients/cli/commands/docs.mjs +184 -70
- package/clients/cli/commands/docs.test.mjs +120 -16
- 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 +3 -3
- 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 +20 -8
- 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 +2 -0
- package/clients/cli/formatters/index.test.mjs +6 -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 +32 -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 +246 -89
- package/foundation/config/project.test.mjs +270 -21
- package/foundation/discovery/authoring-self-docs.d.mts +18 -0
- package/foundation/discovery/authoring-self-docs.mjs +38 -15
- package/foundation/discovery/authoring-self-docs.test.mjs +87 -12
- 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 +38 -0
- package/foundation/discovery/component-discovery.mjs +48 -0
- package/foundation/discovery/component-loader.d.mts +35 -38
- package/foundation/discovery/component-loader.mjs +53 -222
- package/foundation/discovery/docs-discovery.d.mts +114 -9
- package/foundation/discovery/docs-discovery.mjs +239 -30
- package/foundation/discovery/docs-discovery.test.mjs +150 -35
- package/foundation/discovery/docs-output-budget.d.mts +2 -2
- package/foundation/discovery/docs-output-budget.mjs +1 -1
- package/foundation/discovery/docs-section-key.d.mts +28 -10
- package/foundation/discovery/docs-section-key.mjs +134 -33
- package/foundation/discovery/docs-section-key.test.mjs +41 -19
- 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 +772 -82
- 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/integrations/autolink.d.mts +58 -1
- package/foundation/integrations/autolink.mjs +143 -52
- 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 +51 -26
- package/foundation/integrations/integration-warnings.test.mjs +74 -1
- package/foundation/integrations/integrations.d.mts +17 -1
- package/foundation/integrations/integrations.mjs +52 -98
- package/foundation/integrations/integrations.test.mjs +31 -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.mjs +121 -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 +11 -0
- 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 +37 -22
- 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
|
@@ -23,13 +23,15 @@
|
|
|
23
23
|
|
|
24
24
|
import * as fs from 'node:fs';
|
|
25
25
|
import * as path from 'node:path';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
26
|
+
import {createRequire} from 'node:module';
|
|
27
|
+
import {readDocView} from '../doc-compiler/read.mjs';
|
|
28
|
+
import {importDocModule} from '../doc-compiler/import.mjs';
|
|
29
29
|
import {CLI_ROOT, discoverExternalPackages} from '../fs/paths.mjs';
|
|
30
30
|
import {CORE_PROVIDER_ID} from '../identity/providers.mjs';
|
|
31
31
|
import {Project} from '../config/project.mjs';
|
|
32
32
|
|
|
33
|
+
const require = createRequire(import.meta.url);
|
|
34
|
+
|
|
33
35
|
/** Identity used for core (built-in) templates in package-scoped listings. */
|
|
34
36
|
const CORE_PACKAGE = CORE_PROVIDER_ID;
|
|
35
37
|
|
|
@@ -43,6 +45,53 @@ export function pkgOf(t) {
|
|
|
43
45
|
return t.package ?? CORE_PACKAGE;
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Every id that should resolve to a discovered template. Replacements keep
|
|
50
|
+
* their own integration id and also own the Core id they replace.
|
|
51
|
+
* @param {{dirName: string, replaces?: string}} template
|
|
52
|
+
* @returns {string[]}
|
|
53
|
+
*/
|
|
54
|
+
export function templateLookupIds(template) {
|
|
55
|
+
if (template.replaces && template.replaces !== template.dirName) {
|
|
56
|
+
return [template.dirName, template.replaces];
|
|
57
|
+
}
|
|
58
|
+
return [template.dirName];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Remove entries shadowed in the default discovery view while retaining them in
|
|
63
|
+
* package-scoped views. An active replacement owns its target id. A rejected
|
|
64
|
+
* same-id declaration falls back to Core when a Core template of the same kind
|
|
65
|
+
* owns that id; otherwise the integration template remains available by kind.
|
|
66
|
+
* @param {DiscoveredTemplate[]} templates
|
|
67
|
+
* @returns {DiscoveredTemplate[]}
|
|
68
|
+
*/
|
|
69
|
+
export function effectiveTemplateDiscovery(templates) {
|
|
70
|
+
const activeTargets = new Set(
|
|
71
|
+
templates
|
|
72
|
+
.filter(template => template.replaces != null)
|
|
73
|
+
.map(template => `${template.type}:${template.replaces}`),
|
|
74
|
+
);
|
|
75
|
+
const coreIds = new Set(
|
|
76
|
+
templates
|
|
77
|
+
.filter(template => pkgOf(template) === CORE_PACKAGE)
|
|
78
|
+
.map(template => `${template.type}:${template.dirName}`),
|
|
79
|
+
);
|
|
80
|
+
return templates.filter(template => {
|
|
81
|
+
if (
|
|
82
|
+
template.replacementRejected &&
|
|
83
|
+
template.replacementTarget === template.dirName &&
|
|
84
|
+
coreIds.has(`${template.type}:${template.dirName}`)
|
|
85
|
+
) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return (
|
|
89
|
+
!activeTargets.has(`${template.type}:${template.dirName}`) ||
|
|
90
|
+
template.replaces != null
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
46
95
|
/**
|
|
47
96
|
* A discovered template (page or block), normalized across core, external, and
|
|
48
97
|
* integration sources. Not every source populates every field, so
|
|
@@ -65,6 +114,11 @@ export function pkgOf(t) {
|
|
|
65
114
|
* @property {string} filePath
|
|
66
115
|
* @property {string} docPath
|
|
67
116
|
* @property {string} [package]
|
|
117
|
+
* @property {boolean} [autolinked] whether the owning integration was discovered
|
|
118
|
+
* from package.json rather than named in astryx.config
|
|
119
|
+
* @property {string} [replaces] active Core template id this integration template replaces
|
|
120
|
+
* @property {boolean} [replacementRejected] whether an invalid declaration was disabled
|
|
121
|
+
* @property {string} [replacementTarget] disabled declaration target
|
|
68
122
|
*/
|
|
69
123
|
|
|
70
124
|
/**
|
|
@@ -73,6 +127,15 @@ export function pkgOf(t) {
|
|
|
73
127
|
* @property {string} package
|
|
74
128
|
* @property {string} [template]
|
|
75
129
|
* @property {string} message
|
|
130
|
+
* @property {string} [code]
|
|
131
|
+
* @property {'warning' | 'error'} [severity]
|
|
132
|
+
* @property {string} [replacementTarget] Core target whose replacement set is invalid
|
|
133
|
+
* @property {boolean} [autolinked] whether the declaration came from an autolinked integration
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* A semantic error in an integration template replacement declaration.
|
|
138
|
+
* @typedef {TemplateDiscoveryError & {code: 'missing_template_replacement_target' | 'ambiguous_template_replacement' | 'invalid_template_replacement', severity: 'warning' | 'error'}} TemplateReplacementError
|
|
76
139
|
*/
|
|
77
140
|
|
|
78
141
|
/**
|
|
@@ -81,31 +144,28 @@ export function pkgOf(t) {
|
|
|
81
144
|
*/
|
|
82
145
|
|
|
83
146
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* name.
|
|
147
|
+
* Released compatibility suffixes, in precedence order. Stable 0.6.0
|
|
148
|
+
* documented `.template.*`, so discovery keeps reading those files while all
|
|
149
|
+
* new authoring uses `.doc.mjs`.
|
|
88
150
|
*/
|
|
89
151
|
const TEMPLATE_SUFFIXES = ['.template.ts', '.template.mjs', '.template.js'];
|
|
90
152
|
|
|
91
153
|
/**
|
|
92
|
-
*
|
|
93
|
-
* `.doc
|
|
94
|
-
* had their own name; it is still accepted during the transition window.
|
|
154
|
+
* Descriptor suffixes for templates, in precedence order. New authoring always
|
|
155
|
+
* emits `.doc.mjs`; the TypeScript and JavaScript variants remain readable.
|
|
95
156
|
*/
|
|
96
157
|
const DOC_SUFFIXES = ['.doc.ts', '.doc.mjs', '.doc.js'];
|
|
97
158
|
|
|
98
159
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* like a legacy `Foo.doc.mjs`.
|
|
160
|
+
* Every template-spec suffix, in the released precedence a core page directory
|
|
161
|
+
* uses to pick one file. Integration discovery never picks: every match is a
|
|
162
|
+
* template, so two specs for one stem list twice and read as ambiguous.
|
|
103
163
|
*/
|
|
104
164
|
const ALL_TEMPLATE_SUFFIXES = [...TEMPLATE_SUFFIXES, ...DOC_SUFFIXES];
|
|
105
165
|
|
|
106
166
|
/**
|
|
107
167
|
* The template-spec suffix present on `file`, or null if none matches.
|
|
108
|
-
* Recognizes both the canonical `.
|
|
168
|
+
* Recognizes both the canonical `.doc.*` and released `.template.*` families.
|
|
109
169
|
* @param {string} file
|
|
110
170
|
* @returns {string | null}
|
|
111
171
|
*/
|
|
@@ -119,16 +179,6 @@ function matchedTemplateSuffix(file) {
|
|
|
119
179
|
*/
|
|
120
180
|
const TEMPLATE_SUFFIX_RE = /\.(template|doc)\.(ts|mjs|js)$/;
|
|
121
181
|
|
|
122
|
-
/** @type {ReturnType<typeof createJiti> | undefined} */
|
|
123
|
-
let jitiInstance;
|
|
124
|
-
/** Lazily-created jiti for loading `.ts` template specs (JSX-capable). */
|
|
125
|
-
function getJiti() {
|
|
126
|
-
if (!jitiInstance) {
|
|
127
|
-
jitiInstance = createJiti(import.meta.url, {jsx: true});
|
|
128
|
-
}
|
|
129
|
-
return jitiInstance;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
182
|
/**
|
|
133
183
|
* Load an integration template doc module and validate it against the template
|
|
134
184
|
* envelope at the load boundary. Default export only — `.ts` via jiti,
|
|
@@ -141,7 +191,13 @@ function getJiti() {
|
|
|
141
191
|
* @param {string} [label]
|
|
142
192
|
*/
|
|
143
193
|
async function loadIntegrationDoc(file, label) {
|
|
144
|
-
return
|
|
194
|
+
return readDocView(file, {
|
|
195
|
+
root: 'templates',
|
|
196
|
+
exports: ['default'],
|
|
197
|
+
label: label ?? file,
|
|
198
|
+
strict: true,
|
|
199
|
+
value: 'parsed',
|
|
200
|
+
});
|
|
145
201
|
}
|
|
146
202
|
|
|
147
203
|
const TEMPLATES_DIR = path.join(CLI_ROOT, 'assets', 'templates');
|
|
@@ -185,17 +241,53 @@ const IMAGE_EXTENSIONS = new Set([
|
|
|
185
241
|
]);
|
|
186
242
|
|
|
187
243
|
/**
|
|
188
|
-
*
|
|
244
|
+
* First path segment of every Astryx template fixture. Template demo imagery
|
|
189
245
|
* is self-hosted under the docsite's `/template-assets/*` dir (committed there,
|
|
190
|
-
* mirrored into the sandbox preview by scripts/sync-templates.js)
|
|
191
|
-
* only resolve inside the Astryx docsite/sandbox
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* paypalobjects.com) are intentionally left untouched.
|
|
195
|
-
*
|
|
196
|
-
* @type {RegExp}
|
|
246
|
+
* mirrored into the sandbox preview by scripts/sync-templates.js), so those
|
|
247
|
+
* paths only resolve inside the Astryx docsite/sandbox and are replaced on
|
|
248
|
+
* scaffold. Only a root-relative URL whose first segment this is counts: the
|
|
249
|
+
* same text inside a third-party URL or a product path is left untouched.
|
|
197
250
|
*/
|
|
198
|
-
const
|
|
251
|
+
const FIXTURE_SEGMENT = 'template-assets';
|
|
252
|
+
|
|
253
|
+
/** Characters that end a URL token in template source, besides whitespace. */
|
|
254
|
+
const TOKEN_DELIMITERS = new Set([
|
|
255
|
+
"'",
|
|
256
|
+
'"',
|
|
257
|
+
'`',
|
|
258
|
+
'(',
|
|
259
|
+
')',
|
|
260
|
+
'<',
|
|
261
|
+
'>',
|
|
262
|
+
'{',
|
|
263
|
+
'}',
|
|
264
|
+
'[',
|
|
265
|
+
']',
|
|
266
|
+
'\\',
|
|
267
|
+
'|',
|
|
268
|
+
'^',
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
/** The closing delimiter each opening delimiter must pair with. */
|
|
272
|
+
const CLOSING_DELIMITERS = new Map([
|
|
273
|
+
["'", "'"],
|
|
274
|
+
['"', '"'],
|
|
275
|
+
['`', '`'],
|
|
276
|
+
['(', ')'],
|
|
277
|
+
]);
|
|
278
|
+
const CLOSERS = new Set(CLOSING_DELIMITERS.values());
|
|
279
|
+
|
|
280
|
+
/** A URL with a scheme: absolute, so never a fixture reference. */
|
|
281
|
+
const ABSOLUTE_URL = /^[a-z][a-z\d+.-]*:/iu;
|
|
282
|
+
|
|
283
|
+
/** What may lead up to the fixture segment inside a relative product path. */
|
|
284
|
+
const RELATIVE_PATH_PREFIX = /^[\w.~%@/-]+$/u;
|
|
285
|
+
|
|
286
|
+
/** Punctuation that ends a sentence or list item after a path in text. */
|
|
287
|
+
const PROSE_PUNCTUATION = new Set(['.', ',', ';', ':', '!', '?']);
|
|
288
|
+
|
|
289
|
+
/** `from`, `import` or `require` right before a quoted module specifier. */
|
|
290
|
+
const MODULE_SPECIFIER_LEAD = /(?:^|[^\w$])(?:from|import|require)\s*\(?$/u;
|
|
199
291
|
|
|
200
292
|
/**
|
|
201
293
|
* Normalize path into Unix path (using forward slashes) for consistent comparison
|
|
@@ -209,36 +301,255 @@ function toPosixPath(p) {
|
|
|
209
301
|
}
|
|
210
302
|
|
|
211
303
|
/**
|
|
212
|
-
* Replace
|
|
213
|
-
* render with zero setup. Images get a self-contained data
|
|
214
|
-
* (which have no equivalent inline placeholder — see
|
|
215
|
-
* stripped to an empty src instead of being
|
|
216
|
-
* Builders drop in their own media either way.
|
|
304
|
+
* Replace each Astryx template fixture reference with a placeholder so
|
|
305
|
+
* scaffolded pages render with zero setup. Images get a self-contained data
|
|
306
|
+
* URI; videos (which have no equivalent inline placeholder — see
|
|
307
|
+
* VIDEO_EXTENSIONS) are stripped to an empty src instead of being
|
|
308
|
+
* mis-replaced with image data. Builders drop in their own media either way.
|
|
309
|
+
*
|
|
310
|
+
* A reference is a URL token that resolves to a root-relative path under
|
|
311
|
+
* FIXTURE_SEGMENT. It is replaced whole, query and fragment included, and
|
|
312
|
+
* classified by the suffix of its last path segment. A reference that cannot
|
|
313
|
+
* be replaced safely throws with its path rather than being guessed at or
|
|
314
|
+
* left behind. Prose is left as written: in text (JSX text, a word inside a
|
|
315
|
+
* longer string) trailing punctuation is not part of a path and a path with
|
|
316
|
+
* no suffix, such as the bare directory, is a mention; inside a comment
|
|
317
|
+
* nothing throws.
|
|
217
318
|
*
|
|
218
319
|
* @param {string} source - Template source code.
|
|
219
320
|
* @returns {string} Source with demo asset references replaced.
|
|
220
321
|
*/
|
|
221
322
|
export function stripTemplateAssetRefs(source) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
323
|
+
const needle = `/${FIXTURE_SEGMENT}`;
|
|
324
|
+
let output = '';
|
|
325
|
+
let copied = 0;
|
|
326
|
+
/** @type {Array<[number, number]> | undefined} */
|
|
327
|
+
let comments;
|
|
328
|
+
let at = source.indexOf(needle);
|
|
329
|
+
while (at !== -1) {
|
|
330
|
+
let start = at;
|
|
331
|
+
while (start > 0 && !isTokenDelimiter(source[start - 1])) start--;
|
|
332
|
+
let end = at + needle.length;
|
|
333
|
+
while (end < source.length && !isTokenDelimiter(source[end])) end++;
|
|
334
|
+
/** @type {{text: string, end: number} | null} */
|
|
335
|
+
let edit;
|
|
336
|
+
try {
|
|
337
|
+
edit = fixtureEdit(source, start, at, end);
|
|
338
|
+
} catch (err) {
|
|
339
|
+
comments ??= commentRanges(source);
|
|
340
|
+
if (!comments.some(([from, to]) => from <= at && at < to)) throw err;
|
|
341
|
+
edit = null;
|
|
226
342
|
}
|
|
227
|
-
if (
|
|
228
|
-
|
|
343
|
+
if (edit) {
|
|
344
|
+
output += source.slice(copied, start) + edit.text;
|
|
345
|
+
copied = edit.end;
|
|
229
346
|
}
|
|
230
|
-
|
|
231
|
-
}
|
|
347
|
+
at = source.indexOf(needle, end);
|
|
348
|
+
}
|
|
349
|
+
return output + source.slice(copied);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** @param {string | undefined} char */
|
|
353
|
+
function isTokenDelimiter(char) {
|
|
354
|
+
return char === undefined || /\s/u.test(char) || TOKEN_DELIMITERS.has(char);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Whitespace, the source edge, or a tag bracket: what bounds a word of text.
|
|
359
|
+
* @param {string | undefined} char
|
|
360
|
+
*/
|
|
361
|
+
function isTextDelimiter(char) {
|
|
362
|
+
return char === undefined || /\s/u.test(char) || char === '<' || char === '>';
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* The path segments of a root-relative URL under FIXTURE_SEGMENT, or null.
|
|
367
|
+
* @param {string} reference
|
|
368
|
+
* @returns {string[] | null}
|
|
369
|
+
*/
|
|
370
|
+
function fixtureSegments(reference) {
|
|
371
|
+
if (!reference.startsWith('/') || reference.startsWith('//')) return null;
|
|
372
|
+
const segments = new URL(reference, 'http://template.invalid').pathname.split(
|
|
373
|
+
'/',
|
|
374
|
+
);
|
|
375
|
+
return segments[1] === FIXTURE_SEGMENT ? segments : null;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* The replacement for the fixture reference in the URL token [start, end),
|
|
380
|
+
* which contains FIXTURE_SEGMENT's path at `at`; null when the token is not a
|
|
381
|
+
* fixture reference or is a prose mention.
|
|
382
|
+
* @param {string} source
|
|
383
|
+
* @param {number} start
|
|
384
|
+
* @param {number} at
|
|
385
|
+
* @param {number} end
|
|
386
|
+
* @returns {{text: string, end: number} | null}
|
|
387
|
+
*/
|
|
388
|
+
function fixtureEdit(source, start, at, end) {
|
|
389
|
+
const token = source.slice(start, end);
|
|
390
|
+
if (ABSOLUTE_URL.test(token)) return null;
|
|
391
|
+
if (!token.startsWith('/')) {
|
|
392
|
+
if (!fixtureSegments(source.slice(at, end))) return null;
|
|
393
|
+
if (
|
|
394
|
+
source[start - 1] !== '\\' &&
|
|
395
|
+
RELATIVE_PATH_PREFIX.test(source.slice(start, at))
|
|
396
|
+
) {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
throw unsafeFixtureReference(
|
|
400
|
+
source,
|
|
401
|
+
at,
|
|
402
|
+
'it is joined to text the copy cannot parse',
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const before = source[start - 1];
|
|
407
|
+
const after = source[end];
|
|
408
|
+
if (after === '{' && token.endsWith('$')) {
|
|
409
|
+
if (!fixtureSegments(token.slice(0, -1))) return null;
|
|
410
|
+
throw unsafeFixtureReference(
|
|
411
|
+
source,
|
|
412
|
+
at,
|
|
413
|
+
'it is built by a template-literal interpolation',
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
const quoted =
|
|
417
|
+
before !== undefined && CLOSING_DELIMITERS.get(before) === after;
|
|
418
|
+
const escapedQuoted =
|
|
419
|
+
(before === "'" || before === '"') &&
|
|
420
|
+
source[start - 2] === '\\' &&
|
|
421
|
+
after === '\\' &&
|
|
422
|
+
source[end + 1] === before;
|
|
423
|
+
const whole = quoted || escapedQuoted;
|
|
424
|
+
let referenceEnd = end;
|
|
425
|
+
if (!whole) {
|
|
426
|
+
while (
|
|
427
|
+
referenceEnd > at &&
|
|
428
|
+
PROSE_PUNCTUATION.has(source[referenceEnd - 1])
|
|
429
|
+
) {
|
|
430
|
+
referenceEnd--;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const segments = fixtureSegments(source.slice(start, referenceEnd));
|
|
434
|
+
if (!segments) return null;
|
|
435
|
+
|
|
436
|
+
const inText =
|
|
437
|
+
(isTextDelimiter(before) || CLOSING_DELIMITERS.has(before)) &&
|
|
438
|
+
(isTextDelimiter(after) || CLOSERS.has(after)) &&
|
|
439
|
+
(isTextDelimiter(before) || isTextDelimiter(after));
|
|
440
|
+
if (!whole && !inText) {
|
|
441
|
+
throw unsafeFixtureReference(
|
|
442
|
+
source,
|
|
443
|
+
at,
|
|
444
|
+
'it is not a whole quoted, url(), or text value',
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
if (quoted && before !== '(') {
|
|
448
|
+
const use = expressionUse(source, start - 1, end);
|
|
449
|
+
if (use) throw unsafeFixtureReference(source, at, use);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const ext = path.posix
|
|
453
|
+
.extname(segments[segments.length - 1])
|
|
454
|
+
.slice(1)
|
|
455
|
+
.toLowerCase();
|
|
456
|
+
if (VIDEO_EXTENSIONS.has(ext)) return {text: '', end: referenceEnd};
|
|
457
|
+
if (IMAGE_EXTENSIONS.has(ext)) {
|
|
458
|
+
return {text: PLACEHOLDER_IMAGE, end: referenceEnd};
|
|
459
|
+
}
|
|
460
|
+
if (whole || ext) {
|
|
461
|
+
throw new Error(
|
|
462
|
+
`Unrecognized template asset format ${ext || '(none)'} for ${displayReference(source, at)}`,
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Why the string quoted at `open` and `close` cannot be replaced on its own,
|
|
470
|
+
* or null when it is a plain value.
|
|
471
|
+
* @param {string} source
|
|
472
|
+
* @param {number} open
|
|
473
|
+
* @param {number} close
|
|
474
|
+
* @returns {string | null}
|
|
475
|
+
*/
|
|
476
|
+
function expressionUse(source, open, close) {
|
|
477
|
+
let prev = open - 1;
|
|
478
|
+
while (prev >= 0 && /\s/u.test(source[prev])) prev--;
|
|
479
|
+
let next = close + 1;
|
|
480
|
+
while (next < source.length && /\s/u.test(source[next])) next++;
|
|
481
|
+
if (
|
|
482
|
+
source[prev] === '+' ||
|
|
483
|
+
(source[prev] === '=' && source[prev - 1] === '+') ||
|
|
484
|
+
source[next] === '+'
|
|
485
|
+
) {
|
|
486
|
+
return 'the string is concatenated with another value';
|
|
487
|
+
}
|
|
488
|
+
if (source[next] === '.' && /[A-Za-z_$]/u.test(source[next + 1] ?? '')) {
|
|
489
|
+
return 'a method is called on the string';
|
|
490
|
+
}
|
|
491
|
+
if (
|
|
492
|
+
MODULE_SPECIFIER_LEAD.test(source.slice(Math.max(0, prev - 16), prev + 1))
|
|
493
|
+
) {
|
|
494
|
+
return 'it is imported as a module';
|
|
495
|
+
}
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* The [start, end) range of every comment in `source`, or none when it does
|
|
501
|
+
* not parse as TSX.
|
|
502
|
+
* @param {string} source
|
|
503
|
+
* @returns {Array<[number, number]>}
|
|
504
|
+
*/
|
|
505
|
+
function commentRanges(source) {
|
|
506
|
+
try {
|
|
507
|
+
const {parse} = require('@babel/parser');
|
|
508
|
+
const {comments} = parse(source, {
|
|
509
|
+
sourceType: 'module',
|
|
510
|
+
plugins: ['jsx', 'typescript'],
|
|
511
|
+
});
|
|
512
|
+
return (comments ?? []).map(
|
|
513
|
+
comment =>
|
|
514
|
+
/** @type {[number, number]} */ ([
|
|
515
|
+
comment.start ?? 0,
|
|
516
|
+
comment.end ?? 0,
|
|
517
|
+
]),
|
|
518
|
+
);
|
|
519
|
+
} catch {
|
|
520
|
+
return [];
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* The fixture path at `at`, up to the next whitespace, quote, or tag bracket.
|
|
526
|
+
* @param {string} source
|
|
527
|
+
* @param {number} at
|
|
528
|
+
*/
|
|
529
|
+
function displayReference(source, at) {
|
|
530
|
+
let end = at;
|
|
531
|
+
while (end < source.length && !/[\s'"`<>]/u.test(source[end])) end++;
|
|
532
|
+
return source.slice(at, end);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* @param {string} source
|
|
537
|
+
* @param {number} at
|
|
538
|
+
* @param {string} reason
|
|
539
|
+
*/
|
|
540
|
+
function unsafeFixtureReference(source, at, reason) {
|
|
541
|
+
return new Error(
|
|
542
|
+
`Template asset reference ${displayReference(source, at)} cannot be replaced safely: ${reason}. Use the complete path as one static string.`,
|
|
543
|
+
);
|
|
232
544
|
}
|
|
233
545
|
/**
|
|
234
546
|
* Load a template-spec module and return its metadata object. Supports both
|
|
235
547
|
* families of suffix:
|
|
236
|
-
* -
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* Prefers the default export, falling back to the named `doc` export
|
|
240
|
-
*
|
|
241
|
-
* `Foo.doc.mjs` (`doc` export). `.ts` is loaded via jiti; `.mjs`/`.js` via a
|
|
548
|
+
* - Canonical `.doc.*` specs may export the stamped object (`type: 'page' |
|
|
549
|
+
* 'block'`) as the default export or use the historical named `doc` export.
|
|
550
|
+
* - Released `.template.*` compatibility specs use the same object shape.
|
|
551
|
+
* Prefers the default export, falling back to the named `doc` export. `.ts` is
|
|
552
|
+
* loaded via jiti; `.mjs`/`.js` via a
|
|
242
553
|
* native dynamic import. Returns null if the file does not exist.
|
|
243
554
|
*
|
|
244
555
|
* @param {string} docPath absolute path to the spec file
|
|
@@ -246,10 +557,7 @@ export function stripTemplateAssetRefs(source) {
|
|
|
246
557
|
*/
|
|
247
558
|
async function loadDocModule(docPath) {
|
|
248
559
|
if (!fs.existsSync(docPath)) return null;
|
|
249
|
-
|
|
250
|
-
? await getJiti().import(docPath)
|
|
251
|
-
: await import(`file://${docPath}`);
|
|
252
|
-
return docModule.default ?? docModule.doc;
|
|
560
|
+
return readDocView(docPath, {root: 'templates', loader: 'template'});
|
|
253
561
|
}
|
|
254
562
|
|
|
255
563
|
/**
|
|
@@ -294,11 +602,11 @@ function findDocFiles(dir, pattern) {
|
|
|
294
602
|
|
|
295
603
|
/**
|
|
296
604
|
* Resolve the template-spec file for a core page directory: the first existing
|
|
297
|
-
*
|
|
605
|
+
* metadata file in {@link ALL_TEMPLATE_SUFFIXES} precedence, or null.
|
|
298
606
|
* @param {string} dirPath
|
|
299
607
|
* @returns {string | null}
|
|
300
608
|
*/
|
|
301
|
-
function findPageDocFile(dirPath) {
|
|
609
|
+
export function findPageDocFile(dirPath) {
|
|
302
610
|
for (const suffix of ALL_TEMPLATE_SUFFIXES) {
|
|
303
611
|
const candidate = path.join(dirPath, `template${suffix}`);
|
|
304
612
|
if (fs.existsSync(candidate)) return candidate;
|
|
@@ -437,44 +745,297 @@ export async function discoverCoreTemplates() {
|
|
|
437
745
|
}
|
|
438
746
|
|
|
439
747
|
/**
|
|
748
|
+
* Apply valid integration replacements to a raw template set.
|
|
749
|
+
*
|
|
750
|
+
* One declaration owns its Core target. When different configured packages
|
|
751
|
+
* replace the same target, the later package wins and discovery returns a
|
|
752
|
+
* warning, matching integration-doc replacement order. Multiple declarations
|
|
753
|
+
* inside one package are invalid and fail closed. Missing targets and kind
|
|
754
|
+
* mismatches also fail closed: Core stays selected and every integration
|
|
755
|
+
* template remains addressable by its own id.
|
|
756
|
+
*
|
|
757
|
+
* @param {DiscoveredTemplate[]} templates
|
|
758
|
+
* @param {TemplateDiscoveryError[]} [declarationErrors]
|
|
759
|
+
* @returns {{templates: DiscoveredTemplate[], errors: TemplateReplacementError[]}}
|
|
760
|
+
*/
|
|
761
|
+
export function applyTemplateReplacements(templates, declarationErrors = []) {
|
|
762
|
+
/** @type {Map<string, DiscoveredTemplate[]>} */
|
|
763
|
+
const coreById = new Map();
|
|
764
|
+
/** @type {Map<string, DiscoveredTemplate[]>} */
|
|
765
|
+
const replacementsByTarget = new Map();
|
|
766
|
+
|
|
767
|
+
for (const template of templates) {
|
|
768
|
+
if (pkgOf(template) === CORE_PACKAGE) {
|
|
769
|
+
const matches = coreById.get(template.dirName) ?? [];
|
|
770
|
+
matches.push(template);
|
|
771
|
+
coreById.set(template.dirName, matches);
|
|
772
|
+
}
|
|
773
|
+
if (template.replaces != null) {
|
|
774
|
+
const replacements = replacementsByTarget.get(template.replaces) ?? [];
|
|
775
|
+
replacements.push(template);
|
|
776
|
+
replacementsByTarget.set(template.replaces, replacements);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
const activeReplacements = new Set();
|
|
781
|
+
const replacedCore = new Set();
|
|
782
|
+
/** @type {TemplateReplacementError[]} */
|
|
783
|
+
const errors = declarationErrors.map(error => ({
|
|
784
|
+
...error,
|
|
785
|
+
code: /** @type {TemplateReplacementError['code']} */ (
|
|
786
|
+
error.code ?? 'invalid_template_replacement'
|
|
787
|
+
),
|
|
788
|
+
severity: error.severity ?? 'error',
|
|
789
|
+
}));
|
|
790
|
+
/** @param {TemplateReplacementError} error */
|
|
791
|
+
const pushError = error => {
|
|
792
|
+
if (
|
|
793
|
+
errors.some(
|
|
794
|
+
existing =>
|
|
795
|
+
existing.code === error.code &&
|
|
796
|
+
existing.package === error.package &&
|
|
797
|
+
existing.template === error.template &&
|
|
798
|
+
existing.message === error.message,
|
|
799
|
+
)
|
|
800
|
+
) {
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
errors.push(error);
|
|
804
|
+
};
|
|
805
|
+
for (const [target, replacements] of replacementsByTarget) {
|
|
806
|
+
const targetErrors = errors.filter(
|
|
807
|
+
error => error.replacementTarget === target,
|
|
808
|
+
);
|
|
809
|
+
const hasExplicitIntent =
|
|
810
|
+
replacements.some(replacement => !replacement.autolinked) ||
|
|
811
|
+
targetErrors.some(error => !error.autolinked);
|
|
812
|
+
const contenders = hasExplicitIntent
|
|
813
|
+
? replacements.filter(replacement => !replacement.autolinked)
|
|
814
|
+
: replacements;
|
|
815
|
+
let targetInvalid = targetErrors.some(
|
|
816
|
+
error =>
|
|
817
|
+
error.severity === 'error' && (!hasExplicitIntent || !error.autolinked),
|
|
818
|
+
);
|
|
819
|
+
|
|
820
|
+
/** @type {Map<string, DiscoveredTemplate[]>} */
|
|
821
|
+
const byPackage = new Map();
|
|
822
|
+
for (const replacement of replacements) {
|
|
823
|
+
const pkg = pkgOf(replacement);
|
|
824
|
+
const fromPackage = byPackage.get(pkg) ?? [];
|
|
825
|
+
fromPackage.push(replacement);
|
|
826
|
+
byPackage.set(pkg, fromPackage);
|
|
827
|
+
}
|
|
828
|
+
for (const [pkg, declarations] of byPackage) {
|
|
829
|
+
if (declarations.length < 2) continue;
|
|
830
|
+
if (!hasExplicitIntent || !declarations[0].autolinked) {
|
|
831
|
+
targetInvalid = true;
|
|
832
|
+
}
|
|
833
|
+
const message =
|
|
834
|
+
`${pkg} declares ${declarations.length} templates as replacements for Core ` +
|
|
835
|
+
`template "${target}" (${declarations.map(template => template.dirName).join(', ')}). ` +
|
|
836
|
+
'One package must declare at most one replacement for a Core target.';
|
|
837
|
+
for (const declaration of declarations) {
|
|
838
|
+
pushError({
|
|
839
|
+
code: 'ambiguous_template_replacement',
|
|
840
|
+
severity: 'error',
|
|
841
|
+
package: pkg,
|
|
842
|
+
template: declaration.dirName,
|
|
843
|
+
replacementTarget: target,
|
|
844
|
+
autolinked: declaration.autolinked,
|
|
845
|
+
message,
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
const coreMatches = coreById.get(target) ?? [];
|
|
851
|
+
/** @type {Map<DiscoveredTemplate, DiscoveredTemplate>} */
|
|
852
|
+
const coreMatchByReplacement = new Map();
|
|
853
|
+
for (const replacement of replacements) {
|
|
854
|
+
const invalidAffectsTarget =
|
|
855
|
+
!hasExplicitIntent || !replacement.autolinked;
|
|
856
|
+
if (coreMatches.length === 0) {
|
|
857
|
+
if (invalidAffectsTarget) targetInvalid = true;
|
|
858
|
+
pushError({
|
|
859
|
+
code: 'missing_template_replacement_target',
|
|
860
|
+
severity: 'error',
|
|
861
|
+
package: pkgOf(replacement),
|
|
862
|
+
template: replacement.dirName,
|
|
863
|
+
replacementTarget: target,
|
|
864
|
+
autolinked: replacement.autolinked,
|
|
865
|
+
message: `Template "${replacement.dirName}" replaces "${target}", which is not a Core template id.`,
|
|
866
|
+
});
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
const sameType = coreMatches.filter(
|
|
870
|
+
core => core.type === replacement.type,
|
|
871
|
+
);
|
|
872
|
+
if (sameType.length !== 1) {
|
|
873
|
+
if (invalidAffectsTarget) targetInvalid = true;
|
|
874
|
+
const kinds = coreMatches.map(core => core.type).join(', ');
|
|
875
|
+
pushError({
|
|
876
|
+
code: 'invalid_template_replacement',
|
|
877
|
+
severity: 'error',
|
|
878
|
+
package: pkgOf(replacement),
|
|
879
|
+
template: replacement.dirName,
|
|
880
|
+
replacementTarget: target,
|
|
881
|
+
autolinked: replacement.autolinked,
|
|
882
|
+
message:
|
|
883
|
+
`Template "${replacement.dirName}" is a ${replacement.type} template, but Core ` +
|
|
884
|
+
`template "${target}" is ${kinds || 'not available'}. A replacement must have the same type.`,
|
|
885
|
+
});
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
coreMatchByReplacement.set(replacement, sameType[0]);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
const validContenders = contenders.filter(replacement =>
|
|
892
|
+
coreMatchByReplacement.has(replacement),
|
|
893
|
+
);
|
|
894
|
+
if (targetInvalid || validContenders.length === 0) continue;
|
|
895
|
+
|
|
896
|
+
const replacement = validContenders[validContenders.length - 1];
|
|
897
|
+
const validReplacements = replacements.filter(candidate =>
|
|
898
|
+
coreMatchByReplacement.has(candidate),
|
|
899
|
+
);
|
|
900
|
+
if (validReplacements.length > 1) {
|
|
901
|
+
const autolinkedLost =
|
|
902
|
+
hasExplicitIntent &&
|
|
903
|
+
validReplacements.some(candidate => candidate.autolinked);
|
|
904
|
+
const allAutolinked = validReplacements.every(
|
|
905
|
+
candidate => candidate.autolinked,
|
|
906
|
+
);
|
|
907
|
+
pushError({
|
|
908
|
+
code: 'ambiguous_template_replacement',
|
|
909
|
+
severity: 'warning',
|
|
910
|
+
package: pkgOf(replacement),
|
|
911
|
+
template: replacement.dirName,
|
|
912
|
+
replacementTarget: target,
|
|
913
|
+
autolinked: replacement.autolinked,
|
|
914
|
+
message: autolinkedLost
|
|
915
|
+
? `Core template "${target}" is replaced by ${validReplacements.map(candidate => pkgOf(candidate)).join(', ')}. ${pkgOf(replacement)} is explicitly configured, so it wins over autolinked integrations.`
|
|
916
|
+
: allAutolinked
|
|
917
|
+
? `Core template "${target}" is replaced by autolinked dependencies ${validReplacements.map(candidate => pkgOf(candidate)).join(', ')}. ${pkgOf(replacement)} is listed later in package.json dependencies, so it wins. Add the intended package to astryx.config integrations to make precedence explicit.`
|
|
918
|
+
: `Core template "${target}" is replaced by ${validReplacements.map(candidate => pkgOf(candidate)).join(', ')}. ${pkgOf(replacement)} is configured later, so it wins.`,
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
activeReplacements.add(replacement);
|
|
923
|
+
const coreMatch = coreMatchByReplacement.get(replacement);
|
|
924
|
+
if (coreMatch) replacedCore.add(coreMatch);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
const effective = templates.flatMap(template => {
|
|
928
|
+
if (replacedCore.has(template)) return [];
|
|
929
|
+
if (template.replaces != null && !activeReplacements.has(template)) {
|
|
930
|
+
const fallback = {
|
|
931
|
+
...template,
|
|
932
|
+
replacementRejected: true,
|
|
933
|
+
replacementTarget: template.replaces,
|
|
934
|
+
};
|
|
935
|
+
delete fallback.replaces;
|
|
936
|
+
return [fallback];
|
|
937
|
+
}
|
|
938
|
+
return [template];
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
return {
|
|
942
|
+
templates: effective.sort((a, b) => a.name.localeCompare(b.name)),
|
|
943
|
+
errors,
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Discover the raw Core, external, and integration template set before
|
|
949
|
+
* replacement declarations are applied.
|
|
440
950
|
* @param {string} [cwd]
|
|
441
|
-
* @returns {Promise<DiscoveredTemplate[]>}
|
|
951
|
+
* @returns {Promise<{templates: DiscoveredTemplate[], errors: TemplateDiscoveryError[]}>}
|
|
442
952
|
*/
|
|
443
|
-
|
|
953
|
+
async function discoverAllSources(cwd = process.cwd()) {
|
|
444
954
|
const [core, external, integration] = await Promise.all([
|
|
445
955
|
discoverCoreTemplates(),
|
|
446
956
|
discoverExternalBlocks(cwd),
|
|
447
957
|
discoverIntegrationTemplates(cwd),
|
|
448
958
|
]);
|
|
449
|
-
return
|
|
959
|
+
return {
|
|
960
|
+
templates: [...core, ...external, ...integration.templates],
|
|
961
|
+
errors: integration.errors,
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Discover every template without hiding replaced Core originals. Internal
|
|
967
|
+
* package-qualified selection uses this view.
|
|
968
|
+
* @param {string} [cwd]
|
|
969
|
+
* @returns {Promise<DiscoveredTemplate[]>}
|
|
970
|
+
*/
|
|
971
|
+
export async function discoverAllUnresolved(cwd = process.cwd()) {
|
|
972
|
+
return (await discoverAllSources(cwd)).templates.sort((a, b) =>
|
|
450
973
|
a.name.localeCompare(b.name),
|
|
451
974
|
);
|
|
452
975
|
}
|
|
453
976
|
|
|
454
977
|
/**
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
978
|
+
* Resolve replacement declarations while retaining package-addressable entries
|
|
979
|
+
* that are shadowed or rejected in the default discovery view.
|
|
980
|
+
* @param {string} [cwd]
|
|
981
|
+
* @returns {Promise<{templates: DiscoveredTemplate[], errors: Array<TemplateDiscoveryError | TemplateReplacementError>}>}
|
|
982
|
+
*/
|
|
983
|
+
async function resolveAllSources(cwd = process.cwd()) {
|
|
984
|
+
const discovered = await discoverAllSources(cwd);
|
|
985
|
+
const replacementErrors = discovered.errors.filter(
|
|
986
|
+
error => error.replacementTarget != null,
|
|
987
|
+
);
|
|
988
|
+
const resolved = applyTemplateReplacements(
|
|
989
|
+
discovered.templates,
|
|
990
|
+
replacementErrors,
|
|
991
|
+
);
|
|
992
|
+
return {
|
|
993
|
+
templates: resolved.templates,
|
|
994
|
+
errors: [
|
|
995
|
+
...discovered.errors.filter(error => error.replacementTarget == null),
|
|
996
|
+
...resolved.errors,
|
|
997
|
+
],
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Discover the resolved catalog before default-view shadowing. Internal
|
|
1003
|
+
* package-qualified selection uses this view.
|
|
1004
|
+
* @param {string} [cwd]
|
|
1005
|
+
* @returns {Promise<DiscoveredTemplate[]>}
|
|
1006
|
+
*/
|
|
1007
|
+
export async function discoverAllResolved(cwd = process.cwd()) {
|
|
1008
|
+
return (await resolveAllSources(cwd)).templates;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* @param {string} [cwd]
|
|
1013
|
+
* @returns {Promise<DiscoveredTemplate[]>}
|
|
1014
|
+
*/
|
|
1015
|
+
export async function discoverAll(cwd = process.cwd()) {
|
|
1016
|
+
return effectiveTemplateDiscovery(await discoverAllResolved(cwd));
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
/**
|
|
1020
|
+
* Like {@link discoverAll} but also returns integration-template discovery and
|
|
1021
|
+
* replacement-declaration errors. Use this when the caller wants to warn about
|
|
1022
|
+
* malformed integration templates or inactive replacement declarations.
|
|
458
1023
|
*
|
|
459
1024
|
* @param {string} [cwd]
|
|
460
|
-
* @returns {Promise<{templates: DiscoveredTemplate[], errors: TemplateDiscoveryError
|
|
1025
|
+
* @returns {Promise<{templates: DiscoveredTemplate[], errors: Array<TemplateDiscoveryError | TemplateReplacementError>}>}
|
|
461
1026
|
*/
|
|
462
1027
|
export async function discoverAllWithErrors(cwd = process.cwd()) {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const templates = [...pages, ...blocks, ...integration.templates].sort(
|
|
469
|
-
(a, b) => a.name.localeCompare(b.name),
|
|
470
|
-
);
|
|
471
|
-
return {templates, errors: integration.errors};
|
|
1028
|
+
const resolved = await resolveAllSources(cwd);
|
|
1029
|
+
return {
|
|
1030
|
+
templates: effectiveTemplateDiscovery(resolved.templates),
|
|
1031
|
+
errors: resolved.errors,
|
|
1032
|
+
};
|
|
472
1033
|
}
|
|
473
1034
|
|
|
474
1035
|
/**
|
|
475
1036
|
* Recursively collect integration template-spec files under `root`.
|
|
476
1037
|
* Returns absolute paths to files ending in one of ALL_TEMPLATE_SUFFIXES
|
|
477
|
-
* (canonical `.
|
|
1038
|
+
* (canonical `.doc.*` or released `.template.*` compatibility files).
|
|
478
1039
|
*
|
|
479
1040
|
* @param {string} root
|
|
480
1041
|
* @returns {string[]}
|
|
@@ -504,7 +1065,7 @@ function findIntegrationDocFiles(root) {
|
|
|
504
1065
|
* Discover templates contributed by configured integrations.
|
|
505
1066
|
*
|
|
506
1067
|
* For each integration with a resolved `templates` root, every
|
|
507
|
-
* `<id>.
|
|
1068
|
+
* canonical `<id>.doc.{mjs,ts,js}` (or released `<id>.template.{ts,mjs,js}`) file is a
|
|
508
1069
|
* template whose id is its path relative to the templates root with the
|
|
509
1070
|
* matched suffix stripped (kebab-case, may be nested). The doc's `type`
|
|
510
1071
|
* (page|block) decides scaffolding — there is no `/pages` vs `/blocks`
|
|
@@ -545,21 +1106,67 @@ async function discoverIntegrationTemplates(cwd = process.cwd()) {
|
|
|
545
1106
|
}
|
|
546
1107
|
|
|
547
1108
|
for (const integration of loadedIntegrations) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
1109
|
+
// One integration's unreadable root must not cost core or the others theirs.
|
|
1110
|
+
try {
|
|
1111
|
+
const result = await discoverIntegrationTemplatesForOne(integration);
|
|
1112
|
+
templates.push(...result.templates);
|
|
1113
|
+
errors.push(...result.errors);
|
|
1114
|
+
} catch (err) {
|
|
1115
|
+
errors.push({
|
|
1116
|
+
package: integration?.name ?? integration?.__spec ?? 'integration',
|
|
1117
|
+
message: err instanceof Error ? err.message : String(err),
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
551
1120
|
}
|
|
552
1121
|
|
|
553
1122
|
return {templates, errors};
|
|
554
1123
|
}
|
|
555
1124
|
|
|
1125
|
+
/**
|
|
1126
|
+
* Report replacement declarations that cannot hold inside one package: two of
|
|
1127
|
+
* its templates replacing the same Core target. Cross-package precedence and
|
|
1128
|
+
* target checks happen in {@link applyTemplateReplacements}.
|
|
1129
|
+
* @param {string} pkg
|
|
1130
|
+
* @param {boolean | undefined} autolinked
|
|
1131
|
+
* @param {DiscoveredTemplate[]} templates
|
|
1132
|
+
* @param {TemplateDiscoveryError[]} errors
|
|
1133
|
+
*/
|
|
1134
|
+
function reportSamePackageReplacements(pkg, autolinked, templates, errors) {
|
|
1135
|
+
/** @type {Map<string, string[]>} */
|
|
1136
|
+
const idsByTarget = new Map();
|
|
1137
|
+
for (const template of templates) {
|
|
1138
|
+
if (template.replaces == null) continue;
|
|
1139
|
+
const ids = idsByTarget.get(template.replaces) ?? [];
|
|
1140
|
+
ids.push(template.dirName);
|
|
1141
|
+
idsByTarget.set(template.replaces, ids);
|
|
1142
|
+
}
|
|
1143
|
+
for (const [target, ids] of idsByTarget) {
|
|
1144
|
+
if (ids.length < 2) continue;
|
|
1145
|
+
const message =
|
|
1146
|
+
`${pkg} declares ${ids.length} templates as replacements for Core template ` +
|
|
1147
|
+
`"${target}" (${ids.join(', ')}). One package must declare at most one ` +
|
|
1148
|
+
'replacement for a Core target.';
|
|
1149
|
+
for (const template of ids) {
|
|
1150
|
+
errors.push({
|
|
1151
|
+
code: 'ambiguous_template_replacement',
|
|
1152
|
+
severity: 'error',
|
|
1153
|
+
package: pkg,
|
|
1154
|
+
autolinked,
|
|
1155
|
+
template,
|
|
1156
|
+
replacementTarget: target,
|
|
1157
|
+
message,
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
556
1163
|
/**
|
|
557
1164
|
* Discover the templates contributed by a SINGLE integration. Same per-template
|
|
558
1165
|
* rules as {@link discoverIntegrationTemplates} (same-stem source required,
|
|
559
1166
|
* page|block type required); broken templates are recorded in `errors` rather
|
|
560
1167
|
* than thrown. Exposed for `doctor integration validate` and template authoring checks.
|
|
561
1168
|
*
|
|
562
|
-
* @param {{name?: string, __spec?: string, templates?: string}} integration
|
|
1169
|
+
* @param {{name?: string, __spec?: string, __autolinked?: boolean, templates?: string}} integration
|
|
563
1170
|
* @returns {Promise<{templates: DiscoveredTemplate[], errors: TemplateDiscoveryError[]}>}
|
|
564
1171
|
*/
|
|
565
1172
|
export async function discoverIntegrationTemplatesForOne(integration) {
|
|
@@ -588,6 +1195,20 @@ export async function discoverIntegrationTemplatesForOne(integration) {
|
|
|
588
1195
|
template: id,
|
|
589
1196
|
message: `Template "${id}" is missing its same-stem source file ${path.basename(sourcePath)}.`,
|
|
590
1197
|
});
|
|
1198
|
+
// A replacement this unusable template declares still counts, so its
|
|
1199
|
+
// target fails closed instead of going to a sibling.
|
|
1200
|
+
const declared = await declaredReplacement(docPath, id);
|
|
1201
|
+
if (declared != null) {
|
|
1202
|
+
errors.push({
|
|
1203
|
+
code: 'invalid_template_replacement',
|
|
1204
|
+
severity: 'error',
|
|
1205
|
+
package: pkgLabel,
|
|
1206
|
+
autolinked: integration.__autolinked,
|
|
1207
|
+
template: id,
|
|
1208
|
+
replacementTarget: declared,
|
|
1209
|
+
message: `Template "${id}" replaces "${declared}", but it cannot be used: it is missing its same-stem source file ${path.basename(sourcePath)}.`,
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
591
1212
|
continue;
|
|
592
1213
|
}
|
|
593
1214
|
|
|
@@ -600,6 +1221,20 @@ export async function discoverIntegrationTemplatesForOne(integration) {
|
|
|
600
1221
|
template: id,
|
|
601
1222
|
message: `Template "${id}" failed to load: ${/** @type {any} */ (err).message}`,
|
|
602
1223
|
});
|
|
1224
|
+
// A replacement this unusable template declares still counts, so its
|
|
1225
|
+
// target fails closed instead of going to a sibling (spec:AST-035 FR4).
|
|
1226
|
+
const declared = await declaredReplacement(docPath, id);
|
|
1227
|
+
if (declared != null) {
|
|
1228
|
+
errors.push({
|
|
1229
|
+
code: 'invalid_template_replacement',
|
|
1230
|
+
severity: 'error',
|
|
1231
|
+
package: pkgLabel,
|
|
1232
|
+
autolinked: integration.__autolinked,
|
|
1233
|
+
template: id,
|
|
1234
|
+
replacementTarget: declared,
|
|
1235
|
+
message: `Template "${id}" replaces "${declared}", but it cannot be used: its metadata does not load.`,
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
603
1238
|
continue;
|
|
604
1239
|
}
|
|
605
1240
|
|
|
@@ -613,6 +1248,18 @@ export async function discoverIntegrationTemplatesForOne(integration) {
|
|
|
613
1248
|
template: id,
|
|
614
1249
|
message: `Template "${id}" is missing a "type" of "page" or "block". Stamp the default export with type: 'page' or type: 'block'.`,
|
|
615
1250
|
});
|
|
1251
|
+
const declared = doc?.replaces ?? (await declaredReplacement(docPath, id));
|
|
1252
|
+
if (declared != null) {
|
|
1253
|
+
errors.push({
|
|
1254
|
+
code: 'invalid_template_replacement',
|
|
1255
|
+
severity: 'error',
|
|
1256
|
+
package: pkgLabel,
|
|
1257
|
+
autolinked: integration.__autolinked,
|
|
1258
|
+
template: id,
|
|
1259
|
+
replacementTarget: declared,
|
|
1260
|
+
message: `Template "${id}" replaces "${declared}", but it cannot be used: it has no "type".`,
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
616
1263
|
continue;
|
|
617
1264
|
}
|
|
618
1265
|
|
|
@@ -640,12 +1287,55 @@ export async function discoverIntegrationTemplatesForOne(integration) {
|
|
|
640
1287
|
filePath: sourcePath,
|
|
641
1288
|
docPath,
|
|
642
1289
|
package: pkgLabel,
|
|
1290
|
+
autolinked: integration.__autolinked,
|
|
1291
|
+
replaces: doc?.replaces,
|
|
643
1292
|
});
|
|
644
1293
|
}
|
|
645
1294
|
|
|
1295
|
+
reportSamePackageReplacements(
|
|
1296
|
+
pkgLabel,
|
|
1297
|
+
integration.__autolinked,
|
|
1298
|
+
templates,
|
|
1299
|
+
errors,
|
|
1300
|
+
);
|
|
646
1301
|
return {templates, errors};
|
|
647
1302
|
}
|
|
648
1303
|
|
|
1304
|
+
/**
|
|
1305
|
+
* The replacement a template doc declares, even when the doc does not validate
|
|
1306
|
+
* or load: an unusable template's declaration still counts, so its target
|
|
1307
|
+
* fails closed (spec:AST-035 FR4). Null when it declares none.
|
|
1308
|
+
* @param {string} docPath
|
|
1309
|
+
* @param {string} id
|
|
1310
|
+
* @returns {Promise<string | null>}
|
|
1311
|
+
*/
|
|
1312
|
+
async function declaredReplacement(docPath, id) {
|
|
1313
|
+
try {
|
|
1314
|
+
const doc = await loadIntegrationDoc(docPath, `Template "${id}"`);
|
|
1315
|
+
return doc?.replaces ?? null;
|
|
1316
|
+
} catch {
|
|
1317
|
+
// The doc does not validate; read what it declares without validating.
|
|
1318
|
+
}
|
|
1319
|
+
try {
|
|
1320
|
+
// The guarded importer: anything the doc writes to stdout as it loads
|
|
1321
|
+
// goes to stderr, so `--json` output stays clean.
|
|
1322
|
+
const raw = (await importDocModule(docPath))?.default;
|
|
1323
|
+
if (raw != null && typeof raw === 'object') {
|
|
1324
|
+
return typeof raw.replaces === 'string' ? raw.replaces : null;
|
|
1325
|
+
}
|
|
1326
|
+
} catch {
|
|
1327
|
+
// The module does not load at all; its text may still name a target.
|
|
1328
|
+
}
|
|
1329
|
+
try {
|
|
1330
|
+
const match = /\breplaces\s*:\s*['"]([^'"\n]+)['"]/u.exec(
|
|
1331
|
+
fs.readFileSync(docPath, 'utf8'),
|
|
1332
|
+
);
|
|
1333
|
+
return match ? match[1] : null;
|
|
1334
|
+
} catch {
|
|
1335
|
+
return null;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
649
1339
|
/**
|
|
650
1340
|
* @param {string} componentName
|
|
651
1341
|
* @param {string} [cwd]
|