@astryxdesign/cli 0.6.3 → 0.6.4-canary.078fd25
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 +152 -107
- 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 +22 -10
- package/api/build/build.test.mjs +219 -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 +208 -53
- 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 +31 -12
- package/api/component/_adapter.mjs +79 -15
- package/api/component/component.d.mts +6 -3
- package/api/component/component.doc.mjs +49 -19
- package/api/component/component.mjs +339 -22
- package/api/component/component.test.mjs +38 -0
- package/api/component/component.type.d.mts +47 -11
- package/api/component/component.type.mjs +76 -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 +277 -41
- package/api/docs/_adapter.mjs +993 -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/docOverlays.test.mjs +27 -1
- 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.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/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 +104 -1
- package/api/doctor/doctor.doc.mjs +18 -8
- package/api/doctor/doctor.mjs +635 -7
- package/api/doctor/doctor.test.mjs +732 -11
- package/api/doctor/doctor.type.d.mts +1 -1
- package/api/doctor/doctor.type.mjs +1 -1
- package/api/gap-report/gap-report.doc.mjs +27 -14
- package/api/hook/_adapter.mjs +19 -5
- package/api/hook/hook.doc.mjs +7 -3
- 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 +2 -1
- package/api/index.mjs +6 -3
- package/api/init/init.doc.mjs +22 -12
- 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 +56 -65
- package/api/integration/add-theme.test.mjs +139 -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 +5 -4
- package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
- package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
- package/api/integration/pack-check.lifecycle-output.test.mjs +107 -0
- package/api/integration/pack-check.mjs +160 -11
- package/api/integration/pack-check.test.mjs +477 -47
- package/api/integration/pack-check.type.d.mts +26 -2
- package/api/integration/pack-check.type.mjs +15 -2
- 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 +2 -1
- package/api/json/envelope-types.test.mjs +76 -0
- package/api/json/index.ts +2 -0
- package/api/json/isError.doc.mjs +2 -1
- 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 +89 -12
- package/api/search/search.doc.mjs +8 -2
- package/api/search/search.mjs +697 -97
- 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 +8 -5
- package/api/swizzle/swizzle.type.d.mts +2 -2
- package/api/swizzle/swizzle.type.mjs +2 -2
- package/api/template/copy/copy.mjs +18 -24
- package/api/template/copy/copy.test.mjs +26 -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 +32 -9
- 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 +2 -2
- 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 +12 -12
- package/api/theme/themeBuild.doc.mjs +21 -17
- package/api/theme/themeList.doc.mjs +6 -3
- package/api/theme/themeListAvailable.doc.mjs +6 -3
- package/api/theme/themePaletteGenerate.doc.mjs +16 -8
- package/api/theme/themeTargets.doc.mjs +4 -2
- package/api/theme/themeTemplate.doc.mjs +8 -3
- 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/files-changed.test.mjs +111 -0
- package/api/upgrade/run/run.mjs +358 -59
- package/api/upgrade/status/status.mjs +2 -2
- package/api/upgrade/upgrade.doc.mjs +32 -23
- package/api/upgrade/upgrade.type.d.mts +43 -5
- package/api/upgrade/upgrade.type.mjs +29 -13
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/__tests__/runner.test.mjs +332 -8
- package/assets/codemods/file-count.test.mjs +163 -0
- package/assets/codemods/integration-discovery.mjs +48 -4
- package/assets/codemods/integration-discovery.test.mjs +73 -0
- package/assets/codemods/integration-runner.mjs +59 -7
- 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 +353 -104
- 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 +12 -1
- package/assets/docs/authoring.doc.mjs +14 -0
- package/assets/docs/browser-support.doc.mjs +11 -11
- package/assets/docs/color.doc.mjs +8 -2
- package/assets/docs/elevation.doc.mjs +6 -4
- package/assets/docs/getting-started.doc.mjs +6 -17
- package/assets/docs/icons.doc.mjs +2 -21
- package/assets/docs/illustrations.doc.mjs +7 -15
- package/assets/docs/internationalization.doc.mjs +7 -5
- package/assets/docs/layout.doc.dense.mjs +132 -84
- package/assets/docs/layout.doc.mjs +134 -78
- package/assets/docs/migration.doc.mjs +19 -21
- package/assets/docs/motion.doc.mjs +16 -3
- package/assets/docs/principles.doc.dense.mjs +5 -5
- package/assets/docs/principles.doc.mjs +14 -6
- package/assets/docs/principles.doc.zh.mjs +6 -6
- package/assets/docs/shape.doc.mjs +8 -3
- package/assets/docs/spacing.doc.mjs +7 -2
- package/assets/docs/styling-libraries.doc.mjs +10 -6
- package/assets/docs/styling.doc.mjs +22 -26
- package/assets/docs/theme.doc.dense.mjs +58 -18
- package/assets/docs/theme.doc.mjs +60 -50
- package/assets/docs/theme.doc.zh.mjs +9 -8
- package/assets/docs/tokens.doc.dense.mjs +2 -2
- package/assets/docs/tokens.doc.mjs +390 -9
- package/assets/docs/tokens.doc.zh.mjs +2 -2
- package/assets/docs/tree/add-a-component.doc.mjs +75 -0
- package/assets/docs/tree/add-a-theme.doc.mjs +85 -0
- package/assets/docs/tree/add-a-topic.doc.mjs +144 -0
- package/assets/docs/tree/agent-guidance.doc.mjs +138 -0
- package/assets/docs/tree/api.doc.mjs +30 -0
- package/assets/docs/tree/block-template.doc.mjs +130 -0
- package/assets/docs/tree/build-the-template.doc.mjs +28 -0
- package/assets/docs/tree/building-blocks.doc.mjs +46 -0
- package/assets/docs/tree/check-your-docs.doc.mjs +137 -0
- package/assets/docs/tree/checks.doc.mjs +119 -0
- package/assets/docs/tree/cli.doc.mjs +23 -0
- package/assets/docs/tree/codemods.doc.mjs +147 -0
- package/assets/docs/tree/commands.doc.mjs +25 -0
- package/assets/docs/tree/component-family.doc.mjs +113 -0
- package/assets/docs/tree/component-imports.doc.mjs +69 -0
- package/assets/docs/tree/component-lookups.doc.mjs +149 -0
- package/assets/docs/tree/components.doc.mjs +23 -0
- package/assets/docs/tree/configuration.doc.mjs +23 -0
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +182 -0
- package/assets/docs/tree/define-the-theme.doc.mjs +118 -0
- package/assets/docs/tree/describe-the-component.doc.mjs +57 -0
- package/assets/docs/tree/docs.doc.mjs +21 -0
- package/assets/docs/tree/document-the-template.doc.mjs +28 -0
- package/assets/docs/tree/document-the-theme.doc.mjs +68 -0
- package/assets/docs/tree/export-template-assets.doc.mjs +147 -0
- package/assets/docs/tree/extend-or-replace.doc.mjs +103 -0
- package/assets/docs/tree/fonts-and-assets.doc.mjs +106 -0
- package/assets/docs/tree/generate-a-palette.doc.mjs +66 -0
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +105 -0
- package/assets/docs/tree/help.doc.mjs +16 -0
- package/assets/docs/tree/integrations.doc.mjs +40 -0
- package/assets/docs/tree/links.doc.mjs +98 -0
- package/assets/docs/tree/package-and-test.doc.mjs +32 -0
- package/assets/docs/tree/page-template.doc.mjs +71 -0
- package/assets/docs/tree/publishing.doc.mjs +111 -0
- package/assets/docs/tree/quick-start.doc.mjs +272 -0
- package/assets/docs/tree/replace-a-core-component.doc.mjs +104 -0
- package/assets/docs/tree/replace-a-core-template.doc.mjs +172 -0
- package/assets/docs/tree/sections-and-placement.doc.mjs +108 -0
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +59 -0
- package/assets/docs/tree/ship.doc.mjs +16 -0
- package/assets/docs/tree/short-and-findable.doc.mjs +108 -0
- package/assets/docs/tree/single-component.doc.mjs +165 -0
- package/assets/docs/tree/start-a-template.doc.mjs +143 -0
- package/assets/docs/tree/subcomponent.doc.mjs +115 -0
- package/assets/docs/tree/template-assets.doc.mjs +64 -0
- package/assets/docs/tree/template-doc-overview.doc.mjs +109 -0
- package/assets/docs/tree/template-fonts.doc.mjs +102 -0
- package/assets/docs/tree/template-grading-rubric.doc.mjs +452 -0
- package/assets/docs/tree/template-icons.doc.mjs +97 -0
- package/assets/docs/tree/template-images-media.doc.mjs +127 -0
- package/assets/docs/tree/template-styles.doc.mjs +93 -0
- package/assets/docs/tree/templates.doc.mjs +34 -0
- package/assets/docs/tree/test-in-an-app.doc.mjs +115 -0
- package/assets/docs/tree/test-template-in-app.doc.mjs +128 -0
- package/assets/docs/tree/themes.doc.mjs +39 -0
- package/assets/docs/tree/troubleshooting.doc.mjs +149 -0
- package/assets/docs/tree/upgrading.doc.mjs +103 -0
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +51 -0
- package/assets/docs/tree/verify-packed-template.doc.mjs +77 -0
- package/assets/docs/tree/versioning.doc.mjs +161 -0
- package/assets/docs/tree/write-good-templates.doc.mjs +64 -0
- package/assets/docs/tree/write-the-template-file.doc.mjs +154 -0
- package/assets/docs/typography.doc.mjs +24 -4
- package/assets/docs/working-with-ai.doc.mjs +34 -26
- 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 +11 -3
- 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 +792 -24
- package/authoring/doctypes/_schema.mjs +549 -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 +43 -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 +12 -3
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +14 -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 +55 -6
- package/authoring/doctypes/reference/type.ts +75 -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 +2 -2
- 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 +22 -13
- 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 +153 -61
- package/clients/cli/commands/component-batch.test.mjs +341 -0
- package/clients/cli/commands/component-ownership.test.mjs +92 -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 +28 -10
- 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 +295 -38
- package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +6 -5
- 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 +143 -8
- package/clients/cli/commands/doctor.doc.mjs +4 -2
- package/clients/cli/commands/doctor.mjs +108 -37
- package/clients/cli/commands/doctor.test.mjs +42 -0
- package/clients/cli/commands/gap-report.doc.mjs +27 -15
- 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 +24 -10
- 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 +39 -13
- package/clients/cli/commands/integration-authoring.test.mjs +74 -19
- package/clients/cli/commands/integration-pack.doc.mjs +6 -10
- package/clients/cli/commands/integration-real-world.test.mjs +4 -10
- package/clients/cli/commands/integration-verify.doc.mjs +22 -0
- package/clients/cli/commands/integration.doc.mjs +5 -5
- package/clients/cli/commands/integration.mjs +75 -43
- 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 +2 -2
- package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
- package/clients/cli/commands/search.doc.mjs +16 -6
- package/clients/cli/commands/search.mjs +49 -11
- package/clients/cli/commands/search.test.mjs +92 -0
- package/clients/cli/commands/setup-nudge.test.mjs +6 -0
- package/clients/cli/commands/swizzle.doc.mjs +4 -3
- package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
- package/clients/cli/commands/template.doc.mjs +53 -14
- 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 +725 -0
- package/clients/cli/commands/theme-add.doc.mjs +5 -4
- 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 +12 -7
- package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
- package/clients/cli/commands/theme-palette.doc.mjs +2 -3
- package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
- package/clients/cli/commands/theme-targets.doc.mjs +3 -3
- 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 +3 -2
- package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
- package/clients/cli/commands/upgrade.doc.mjs +83 -12
- 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 +47 -34
- 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 +56 -6
- package/clients/cli/lib/define-command.test.mjs +54 -0
- package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
- package/clients/cli/lib/exit-codes.test.mjs +113 -0
- package/clients/cli/lib/hook-format.mjs +19 -10
- package/clients/cli/lib/json-shim.mjs +62 -16
- 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 +53 -6
- package/clients/cli/lib/manifest.test.mjs +22 -2
- package/clients/cli/lib/parse-error-format.test.mjs +81 -0
- package/foundation/agent-docs/agent-docs.d.mts +7 -2
- package/foundation/agent-docs/agent-docs.mjs +83 -13
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
- 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 +174 -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 +504 -0
- package/foundation/discovery/cli-self-docs.test.mjs +395 -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 +427 -108
- package/foundation/discovery/docs-discovery.test.mjs +386 -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 +1643 -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 +298 -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 +292 -0
- package/foundation/doc-compiler/tree.mjs +881 -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 +65 -0
- package/foundation/integrations/cli-requirement.mjs +189 -0
- package/foundation/integrations/cli-requirement.test.mjs +89 -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 +28 -25
- 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/batch.type.d.mts +33 -0
- package/foundation/response/batch.type.mjs +34 -0
- 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 +19 -12
- package/foundation/response/error-codes.mjs +8 -2
- package/foundation/response/error-codes.test.mjs +166 -14
- 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 +7 -2
- package/foundation/response/response-types.doc.mjs +69 -25
- package/foundation/response/response-types.doc.test.mjs +181 -0
- package/foundation/response/response.doc.mjs +12 -11
- 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/api/docs/docs.test.mjs +0 -83
- package/api/docs/integrationDocs.test.mjs +0 -208
- package/api/search/search.test.mjs +0 -389
- package/assets/docs/cli-integrations.doc.mjs +0 -367
- package/assets/templates/themes/manifest.json +0 -95
- package/clients/cli/commands/docs.test.mjs +0 -102
- 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
- package/foundation/agent-docs/agent-docs.test.mjs +0 -1141
|
@@ -23,14 +23,17 @@
|
|
|
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
|
+
import {CORE_PROVIDER_ID} from '../identity/providers.mjs';
|
|
30
31
|
import {Project} from '../config/project.mjs';
|
|
31
32
|
|
|
33
|
+
const require = createRequire(import.meta.url);
|
|
34
|
+
|
|
32
35
|
/** Identity used for core (built-in) templates in package-scoped listings. */
|
|
33
|
-
const CORE_PACKAGE =
|
|
36
|
+
const CORE_PACKAGE = CORE_PROVIDER_ID;
|
|
34
37
|
|
|
35
38
|
/**
|
|
36
39
|
* Identity for a template in package-scoped views. Core (built-in) templates
|
|
@@ -42,6 +45,53 @@ export function pkgOf(t) {
|
|
|
42
45
|
return t.package ?? CORE_PACKAGE;
|
|
43
46
|
}
|
|
44
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
|
+
|
|
45
95
|
/**
|
|
46
96
|
* A discovered template (page or block), normalized across core, external, and
|
|
47
97
|
* integration sources. Not every source populates every field, so
|
|
@@ -64,6 +114,11 @@ export function pkgOf(t) {
|
|
|
64
114
|
* @property {string} filePath
|
|
65
115
|
* @property {string} docPath
|
|
66
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
|
|
67
122
|
*/
|
|
68
123
|
|
|
69
124
|
/**
|
|
@@ -72,6 +127,15 @@ export function pkgOf(t) {
|
|
|
72
127
|
* @property {string} package
|
|
73
128
|
* @property {string} [template]
|
|
74
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
|
|
75
139
|
*/
|
|
76
140
|
|
|
77
141
|
/**
|
|
@@ -80,31 +144,28 @@ export function pkgOf(t) {
|
|
|
80
144
|
*/
|
|
81
145
|
|
|
82
146
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* 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`.
|
|
87
150
|
*/
|
|
88
151
|
const TEMPLATE_SUFFIXES = ['.template.ts', '.template.mjs', '.template.js'];
|
|
89
152
|
|
|
90
153
|
/**
|
|
91
|
-
*
|
|
92
|
-
* `.doc
|
|
93
|
-
* 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.
|
|
94
156
|
*/
|
|
95
157
|
const DOC_SUFFIXES = ['.doc.ts', '.doc.mjs', '.doc.js'];
|
|
96
158
|
|
|
97
159
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* 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.
|
|
102
163
|
*/
|
|
103
164
|
const ALL_TEMPLATE_SUFFIXES = [...TEMPLATE_SUFFIXES, ...DOC_SUFFIXES];
|
|
104
165
|
|
|
105
166
|
/**
|
|
106
167
|
* The template-spec suffix present on `file`, or null if none matches.
|
|
107
|
-
* Recognizes both the canonical `.
|
|
168
|
+
* Recognizes both the canonical `.doc.*` and released `.template.*` families.
|
|
108
169
|
* @param {string} file
|
|
109
170
|
* @returns {string | null}
|
|
110
171
|
*/
|
|
@@ -118,16 +179,6 @@ function matchedTemplateSuffix(file) {
|
|
|
118
179
|
*/
|
|
119
180
|
const TEMPLATE_SUFFIX_RE = /\.(template|doc)\.(ts|mjs|js)$/;
|
|
120
181
|
|
|
121
|
-
/** @type {ReturnType<typeof createJiti> | undefined} */
|
|
122
|
-
let jitiInstance;
|
|
123
|
-
/** Lazily-created jiti for loading `.ts` template specs (JSX-capable). */
|
|
124
|
-
function getJiti() {
|
|
125
|
-
if (!jitiInstance) {
|
|
126
|
-
jitiInstance = createJiti(import.meta.url, {jsx: true});
|
|
127
|
-
}
|
|
128
|
-
return jitiInstance;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
182
|
/**
|
|
132
183
|
* Load an integration template doc module and validate it against the template
|
|
133
184
|
* envelope at the load boundary. Default export only — `.ts` via jiti,
|
|
@@ -140,7 +191,13 @@ function getJiti() {
|
|
|
140
191
|
* @param {string} [label]
|
|
141
192
|
*/
|
|
142
193
|
async function loadIntegrationDoc(file, label) {
|
|
143
|
-
return
|
|
194
|
+
return readDocView(file, {
|
|
195
|
+
root: 'templates',
|
|
196
|
+
exports: ['default'],
|
|
197
|
+
label: label ?? file,
|
|
198
|
+
strict: true,
|
|
199
|
+
value: 'parsed',
|
|
200
|
+
});
|
|
144
201
|
}
|
|
145
202
|
|
|
146
203
|
const TEMPLATES_DIR = path.join(CLI_ROOT, 'assets', 'templates');
|
|
@@ -184,17 +241,53 @@ const IMAGE_EXTENSIONS = new Set([
|
|
|
184
241
|
]);
|
|
185
242
|
|
|
186
243
|
/**
|
|
187
|
-
*
|
|
244
|
+
* First path segment of every Astryx template fixture. Template demo imagery
|
|
188
245
|
* is self-hosted under the docsite's `/template-assets/*` dir (committed there,
|
|
189
|
-
* mirrored into the sandbox preview by scripts/sync-templates.js)
|
|
190
|
-
* only resolve inside the Astryx docsite/sandbox
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* paypalobjects.com) are intentionally left untouched.
|
|
194
|
-
*
|
|
195
|
-
* @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.
|
|
196
250
|
*/
|
|
197
|
-
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;
|
|
198
291
|
|
|
199
292
|
/**
|
|
200
293
|
* Normalize path into Unix path (using forward slashes) for consistent comparison
|
|
@@ -208,36 +301,255 @@ function toPosixPath(p) {
|
|
|
208
301
|
}
|
|
209
302
|
|
|
210
303
|
/**
|
|
211
|
-
* Replace
|
|
212
|
-
* render with zero setup. Images get a self-contained data
|
|
213
|
-
* (which have no equivalent inline placeholder — see
|
|
214
|
-
* stripped to an empty src instead of being
|
|
215
|
-
* 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.
|
|
216
318
|
*
|
|
217
319
|
* @param {string} source - Template source code.
|
|
218
320
|
* @returns {string} Source with demo asset references replaced.
|
|
219
321
|
*/
|
|
220
322
|
export function stripTemplateAssetRefs(source) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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;
|
|
225
342
|
}
|
|
226
|
-
if (
|
|
227
|
-
|
|
343
|
+
if (edit) {
|
|
344
|
+
output += source.slice(copied, start) + edit.text;
|
|
345
|
+
copied = edit.end;
|
|
228
346
|
}
|
|
229
|
-
|
|
230
|
-
}
|
|
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
|
+
);
|
|
231
544
|
}
|
|
232
545
|
/**
|
|
233
546
|
* Load a template-spec module and return its metadata object. Supports both
|
|
234
547
|
* families of suffix:
|
|
235
|
-
* -
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
* Prefers the default export, falling back to the named `doc` export
|
|
239
|
-
*
|
|
240
|
-
* `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
|
|
241
553
|
* native dynamic import. Returns null if the file does not exist.
|
|
242
554
|
*
|
|
243
555
|
* @param {string} docPath absolute path to the spec file
|
|
@@ -245,10 +557,7 @@ export function stripTemplateAssetRefs(source) {
|
|
|
245
557
|
*/
|
|
246
558
|
async function loadDocModule(docPath) {
|
|
247
559
|
if (!fs.existsSync(docPath)) return null;
|
|
248
|
-
|
|
249
|
-
? await getJiti().import(docPath)
|
|
250
|
-
: await import(`file://${docPath}`);
|
|
251
|
-
return docModule.default ?? docModule.doc;
|
|
560
|
+
return readDocView(docPath, {root: 'templates', loader: 'template'});
|
|
252
561
|
}
|
|
253
562
|
|
|
254
563
|
/**
|
|
@@ -293,11 +602,11 @@ function findDocFiles(dir, pattern) {
|
|
|
293
602
|
|
|
294
603
|
/**
|
|
295
604
|
* Resolve the template-spec file for a core page directory: the first existing
|
|
296
|
-
*
|
|
605
|
+
* metadata file in {@link ALL_TEMPLATE_SUFFIXES} precedence, or null.
|
|
297
606
|
* @param {string} dirPath
|
|
298
607
|
* @returns {string | null}
|
|
299
608
|
*/
|
|
300
|
-
function findPageDocFile(dirPath) {
|
|
609
|
+
export function findPageDocFile(dirPath) {
|
|
301
610
|
for (const suffix of ALL_TEMPLATE_SUFFIXES) {
|
|
302
611
|
const candidate = path.join(dirPath, `template${suffix}`);
|
|
303
612
|
if (fs.existsSync(candidate)) return candidate;
|
|
@@ -436,44 +745,297 @@ export async function discoverCoreTemplates() {
|
|
|
436
745
|
}
|
|
437
746
|
|
|
438
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.
|
|
439
950
|
* @param {string} [cwd]
|
|
440
|
-
* @returns {Promise<DiscoveredTemplate[]>}
|
|
951
|
+
* @returns {Promise<{templates: DiscoveredTemplate[], errors: TemplateDiscoveryError[]}>}
|
|
441
952
|
*/
|
|
442
|
-
|
|
953
|
+
async function discoverAllSources(cwd = process.cwd()) {
|
|
443
954
|
const [core, external, integration] = await Promise.all([
|
|
444
955
|
discoverCoreTemplates(),
|
|
445
956
|
discoverExternalBlocks(cwd),
|
|
446
957
|
discoverIntegrationTemplates(cwd),
|
|
447
958
|
]);
|
|
448
|
-
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) =>
|
|
449
973
|
a.name.localeCompare(b.name),
|
|
450
974
|
);
|
|
451
975
|
}
|
|
452
976
|
|
|
453
977
|
/**
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
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.
|
|
457
1023
|
*
|
|
458
1024
|
* @param {string} [cwd]
|
|
459
|
-
* @returns {Promise<{templates: DiscoveredTemplate[], errors: TemplateDiscoveryError
|
|
1025
|
+
* @returns {Promise<{templates: DiscoveredTemplate[], errors: Array<TemplateDiscoveryError | TemplateReplacementError>}>}
|
|
460
1026
|
*/
|
|
461
1027
|
export async function discoverAllWithErrors(cwd = process.cwd()) {
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
const templates = [...pages, ...blocks, ...integration.templates].sort(
|
|
468
|
-
(a, b) => a.name.localeCompare(b.name),
|
|
469
|
-
);
|
|
470
|
-
return {templates, errors: integration.errors};
|
|
1028
|
+
const resolved = await resolveAllSources(cwd);
|
|
1029
|
+
return {
|
|
1030
|
+
templates: effectiveTemplateDiscovery(resolved.templates),
|
|
1031
|
+
errors: resolved.errors,
|
|
1032
|
+
};
|
|
471
1033
|
}
|
|
472
1034
|
|
|
473
1035
|
/**
|
|
474
1036
|
* Recursively collect integration template-spec files under `root`.
|
|
475
1037
|
* Returns absolute paths to files ending in one of ALL_TEMPLATE_SUFFIXES
|
|
476
|
-
* (canonical `.
|
|
1038
|
+
* (canonical `.doc.*` or released `.template.*` compatibility files).
|
|
477
1039
|
*
|
|
478
1040
|
* @param {string} root
|
|
479
1041
|
* @returns {string[]}
|
|
@@ -503,7 +1065,7 @@ function findIntegrationDocFiles(root) {
|
|
|
503
1065
|
* Discover templates contributed by configured integrations.
|
|
504
1066
|
*
|
|
505
1067
|
* For each integration with a resolved `templates` root, every
|
|
506
|
-
* `<id>.
|
|
1068
|
+
* canonical `<id>.doc.{mjs,ts,js}` (or released `<id>.template.{ts,mjs,js}`) file is a
|
|
507
1069
|
* template whose id is its path relative to the templates root with the
|
|
508
1070
|
* matched suffix stripped (kebab-case, may be nested). The doc's `type`
|
|
509
1071
|
* (page|block) decides scaffolding — there is no `/pages` vs `/blocks`
|
|
@@ -544,21 +1106,67 @@ async function discoverIntegrationTemplates(cwd = process.cwd()) {
|
|
|
544
1106
|
}
|
|
545
1107
|
|
|
546
1108
|
for (const integration of loadedIntegrations) {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
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
|
+
}
|
|
550
1120
|
}
|
|
551
1121
|
|
|
552
1122
|
return {templates, errors};
|
|
553
1123
|
}
|
|
554
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
|
+
|
|
555
1163
|
/**
|
|
556
1164
|
* Discover the templates contributed by a SINGLE integration. Same per-template
|
|
557
1165
|
* rules as {@link discoverIntegrationTemplates} (same-stem source required,
|
|
558
1166
|
* page|block type required); broken templates are recorded in `errors` rather
|
|
559
1167
|
* than thrown. Exposed for `doctor integration validate` and template authoring checks.
|
|
560
1168
|
*
|
|
561
|
-
* @param {{name?: string, __spec?: string, templates?: string}} integration
|
|
1169
|
+
* @param {{name?: string, __spec?: string, __autolinked?: boolean, templates?: string}} integration
|
|
562
1170
|
* @returns {Promise<{templates: DiscoveredTemplate[], errors: TemplateDiscoveryError[]}>}
|
|
563
1171
|
*/
|
|
564
1172
|
export async function discoverIntegrationTemplatesForOne(integration) {
|
|
@@ -587,6 +1195,20 @@ export async function discoverIntegrationTemplatesForOne(integration) {
|
|
|
587
1195
|
template: id,
|
|
588
1196
|
message: `Template "${id}" is missing its same-stem source file ${path.basename(sourcePath)}.`,
|
|
589
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
|
+
}
|
|
590
1212
|
continue;
|
|
591
1213
|
}
|
|
592
1214
|
|
|
@@ -599,6 +1221,20 @@ export async function discoverIntegrationTemplatesForOne(integration) {
|
|
|
599
1221
|
template: id,
|
|
600
1222
|
message: `Template "${id}" failed to load: ${/** @type {any} */ (err).message}`,
|
|
601
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
|
+
}
|
|
602
1238
|
continue;
|
|
603
1239
|
}
|
|
604
1240
|
|
|
@@ -612,6 +1248,18 @@ export async function discoverIntegrationTemplatesForOne(integration) {
|
|
|
612
1248
|
template: id,
|
|
613
1249
|
message: `Template "${id}" is missing a "type" of "page" or "block". Stamp the default export with type: 'page' or type: 'block'.`,
|
|
614
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
|
+
}
|
|
615
1263
|
continue;
|
|
616
1264
|
}
|
|
617
1265
|
|
|
@@ -639,12 +1287,55 @@ export async function discoverIntegrationTemplatesForOne(integration) {
|
|
|
639
1287
|
filePath: sourcePath,
|
|
640
1288
|
docPath,
|
|
641
1289
|
package: pkgLabel,
|
|
1290
|
+
autolinked: integration.__autolinked,
|
|
1291
|
+
replaces: doc?.replaces,
|
|
642
1292
|
});
|
|
643
1293
|
}
|
|
644
1294
|
|
|
1295
|
+
reportSamePackageReplacements(
|
|
1296
|
+
pkgLabel,
|
|
1297
|
+
integration.__autolinked,
|
|
1298
|
+
templates,
|
|
1299
|
+
errors,
|
|
1300
|
+
);
|
|
645
1301
|
return {templates, errors};
|
|
646
1302
|
}
|
|
647
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
|
+
|
|
648
1339
|
/**
|
|
649
1340
|
* @param {string} componentName
|
|
650
1341
|
* @param {string} [cwd]
|