@astryxdesign/cli 0.6.3 → 0.6.4-canary.06c8fa3
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 +121 -85
- 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 +31 -12
- package/api/component/_adapter.mjs +79 -15
- package/api/component/component.d.mts +6 -3
- package/api/component/component.doc.mjs +36 -13
- 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 +272 -41
- package/api/docs/_adapter.mjs +985 -108
- package/api/docs/compiled-topics.test.mjs +78 -0
- package/api/docs/detail/detail.mjs +22 -63
- package/api/docs/detail/section/section.d.mts +1 -1
- package/api/docs/detail/section/section.mjs +54 -19
- package/api/docs/detail/section/section.test.mjs +50 -0
- package/api/docs/docs.d.mts +10 -3
- package/api/docs/docs.doc.mjs +55 -16
- package/api/docs/docs.mjs +53 -10
- package/api/docs/docs.test.mjs +166 -4
- package/api/docs/docs.type.d.mts +221 -5
- package/api/docs/docs.type.mjs +153 -11
- package/api/docs/index/index.d.mts +18 -0
- package/api/docs/index/index.mjs +40 -0
- package/api/docs/index/index.test.mjs +62 -0
- package/api/docs/integration-tree.test.mjs +555 -0
- package/api/docs/integrationDocs.test.mjs +114 -8
- package/api/docs/list/list.mjs +28 -12
- package/api/docs/node/node.d.mts +43 -0
- package/api/docs/node/node.mjs +192 -0
- package/api/docs/reference-blocks.test.mjs +406 -0
- package/api/doctor/doctor.d.mts +104 -1
- package/api/doctor/doctor.doc.mjs +1 -0
- package/api/doctor/doctor.mjs +635 -7
- package/api/doctor/doctor.test.mjs +732 -11
- package/api/gap-report/gap-report.doc.mjs +8 -4
- package/api/hook/_adapter.mjs +19 -5
- package/api/hook/hook.doc.mjs +1 -0
- package/api/hook/hook.type.d.mts +3 -3
- package/api/hook/hook.type.mjs +11 -11
- package/api/hook/list/list.d.mts +2 -2
- package/api/hook/list/list.mjs +69 -17
- package/api/index.d.mts +2 -3
- package/api/index.mjs +5 -4
- package/api/init/init.doc.mjs +6 -1
- package/api/init/init.test.mjs +41 -1
- package/api/init/remove/remove.mjs +1 -1
- package/api/init/run/run.mjs +20 -10
- package/api/integration/add-contribution.component-names.test.mjs +120 -0
- package/api/integration/add-contribution.d.mts +2 -1
- package/api/integration/add-contribution.mjs +130 -15
- package/api/integration/add-contribution.test.mjs +258 -7
- package/api/integration/add-helpers.d.mts +5 -2
- package/api/integration/add-helpers.mjs +36 -9
- package/api/integration/add-theme.mjs +34 -64
- package/api/integration/add-theme.test.mjs +105 -21
- package/api/integration/authoring-checks.mjs +138 -28
- package/api/integration/authoring-checks.test.mjs +179 -7
- package/api/integration/authoring-checks.type.mjs +6 -1
- package/api/integration/integration-authoring.type.d.mts +3 -1
- package/api/integration/integration-authoring.type.mjs +2 -0
- package/api/integration/integration-block-exports.test.mjs +10 -6
- package/api/integration/integrationAdd.doc.mjs +14 -4
- package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
- package/api/integration/integrationAddCodemod.doc.mjs +1 -0
- package/api/integration/integrationAddComponent.doc.mjs +2 -1
- package/api/integration/integrationAddDoc.doc.mjs +8 -1
- package/api/integration/integrationAddTemplate.doc.mjs +1 -0
- package/api/integration/integrationAddTheme.doc.mjs +6 -5
- package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
- package/api/integration/integrationDocConflicts.doc.mjs +2 -1
- package/api/integration/integrationPackCheck.doc.mjs +2 -1
- package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
- package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
- package/api/integration/pack-check.lifecycle-output.test.mjs +105 -0
- package/api/integration/pack-check.mjs +111 -10
- 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 -1
- package/api/json/isError.doc.mjs +1 -0
- package/api/json/parseResponse.doc.mjs +3 -2
- package/api/search/search-return-type.test.mjs +54 -0
- package/api/search/search.d.mts +62 -11
- package/api/search/search.doc.mjs +8 -2
- package/api/search/search.mjs +471 -83
- package/api/search/search.test.mjs +142 -1
- package/api/search/search.type.d.mts +15 -3
- package/api/search/search.type.mjs +5 -2
- package/api/swizzle/copy/copy.mjs +28 -11
- package/api/swizzle/swizzle.doc.mjs +2 -1
- package/api/swizzle/swizzle.type.d.mts +2 -2
- package/api/swizzle/swizzle.type.mjs +2 -2
- package/api/template/copy/copy.mjs +17 -23
- package/api/template/copy/copy.test.mjs +17 -0
- package/api/template/list/list.mjs +1 -0
- package/api/template/table-floating-bulk-actions.test.mjs +66 -0
- package/api/template/template-integration.test.mjs +1008 -3
- package/api/template/template-suffix.test.mjs +41 -21
- package/api/template/template.d.mts +1 -1
- package/api/template/template.doc.mjs +30 -8
- package/api/template/template.mjs +46 -9
- package/api/template/template.type.d.mts +12 -14
- package/api/template/template.type.mjs +15 -14
- package/api/theme/_adapter.d.mts +2 -3
- package/api/theme/_adapter.mjs +4 -5
- package/api/theme/add/add.binary.test.mjs +84 -0
- package/api/theme/add/add.mjs +31 -22
- package/api/theme/add/add.rollback.test.mjs +158 -0
- package/api/theme/add/add.staging.test.mjs +83 -0
- package/api/theme/add/add.test.mjs +14 -1
- package/api/theme/build/build.family.test.mjs +7 -12
- package/api/theme/build/build.mjs +140 -59
- package/api/theme/build/build.public-component-vars.test.mjs +1 -1
- package/api/theme/build/build.receipt-doc.test.mjs +111 -0
- package/api/theme/build/build.rollback.test.mjs +148 -0
- package/api/theme/build/build.test.mjs +127 -0
- package/api/theme/build/font-warning.mjs +3 -3
- package/api/theme/build/font-warning.test.mjs +5 -2
- package/api/theme/generateTonalPalette.doc.mjs +1 -0
- package/api/theme/integration-themes.test.mjs +39 -28
- package/api/theme/list/list.test.mjs +19 -20
- package/api/theme/listThemes.doc.mjs +6 -5
- package/api/theme/palette/generate/generate.mjs +8 -3
- package/api/theme/palette/generate/generate.test.mjs +96 -0
- package/api/theme/palette/generate/generator.d.mts +10 -13
- package/api/theme/palette/generate/generator.mjs +15 -4
- package/api/theme/palette/generate/generator.test.mjs +10 -0
- package/api/theme/template/template.mjs +11 -2
- package/api/theme/template/template.test.mjs +20 -0
- package/api/theme/theme.type.d.mts +170 -11
- package/api/theme/theme.type.mjs +94 -27
- package/api/theme/themeAdd.doc.mjs +4 -3
- package/api/theme/themeBuild.doc.mjs +8 -4
- package/api/theme/themeList.doc.mjs +6 -3
- package/api/theme/themeListAvailable.doc.mjs +5 -3
- package/api/theme/themePaletteGenerate.doc.mjs +1 -0
- package/api/theme/themeTargets.doc.mjs +1 -0
- package/api/theme/themeTemplate.doc.mjs +6 -2
- package/api/upgrade/_adapter.d.mts +32 -5
- package/api/upgrade/_adapter.mjs +139 -22
- package/api/upgrade/list/list.mjs +2 -1
- package/api/upgrade/list/list.test.mjs +73 -0
- package/api/upgrade/project-context.test.mjs +272 -0
- package/api/upgrade/provider-agreement.test.mjs +152 -0
- package/api/upgrade/run/files-changed.test.mjs +111 -0
- package/api/upgrade/run/run.mjs +359 -60
- package/api/upgrade/status/status.mjs +2 -2
- package/api/upgrade/upgrade.doc.mjs +12 -5
- package/api/upgrade/upgrade.type.d.mts +43 -5
- package/api/upgrade/upgrade.type.mjs +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 +9 -0
- package/assets/docs/authoring.doc.mjs +14 -0
- package/assets/docs/getting-started.doc.mjs +2 -2
- package/assets/docs/internationalization.doc.mjs +7 -5
- package/assets/docs/layout.doc.dense.mjs +2 -2
- package/assets/docs/layout.doc.mjs +1 -1
- package/assets/docs/principles.doc.mjs +6 -6
- package/assets/docs/styling-libraries.doc.mjs +4 -4
- package/assets/docs/styling.doc.mjs +4 -4
- package/assets/docs/theme.doc.mjs +5 -5
- package/assets/docs/tokens.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +30 -0
- package/assets/docs/tree/cli.doc.mjs +23 -0
- package/assets/docs/tree/commands.doc.mjs +25 -0
- package/assets/docs/tree/component-lookups.doc.mjs +149 -0
- package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +144 -26
- package/assets/docs/tree/integrations.test.mjs +62 -0
- package/assets/docs/tree/writing-docs.doc.mjs +286 -0
- package/assets/docs/working-with-ai.doc.mjs +4 -4
- package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
- package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
- package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
- package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
- package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
- package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
- package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
- package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
- package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
- package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
- package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
- package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
- package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
- package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
- package/assets/templates/pages/table-tree/page.tsx +1704 -0
- package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
- package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
- package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
- package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
- package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
- package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
- package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
- package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
- package/authoring/_shared/contract.ts +22 -0
- package/authoring/codemod/codemod.doc.mjs +7 -2
- package/authoring/codemod/parse.d.mts +8 -8
- package/authoring/codemod/parse.mjs +8 -6
- package/authoring/codemod/type.ts +12 -0
- package/authoring/config/config.doc.mjs +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 +31 -8
- package/authoring/debug/debug.doc.d.mts +11 -0
- package/authoring/debug/debug.doc.mjs +182 -0
- package/authoring/debug/parse.d.mts +8 -8
- package/authoring/debug/parse.mjs +3 -3
- package/authoring/discover/discover.doc.d.mts +13 -0
- package/authoring/discover/discover.doc.mjs +138 -0
- package/authoring/discover/parse.d.mts +24 -0
- package/authoring/discover/parse.mjs +128 -0
- package/authoring/discover/parse.test.mjs +124 -0
- package/authoring/discover/type.ts +87 -0
- package/authoring/doctypes/_schema.d.mts +790 -23
- package/authoring/doctypes/_schema.mjs +543 -39
- package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
- package/authoring/doctypes/base/type.ts +41 -0
- package/authoring/doctypes/command/command.doc.mjs +5 -4
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +6 -5
- package/authoring/doctypes/component/component.doc.mjs +6 -3
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +6 -5
- package/authoring/doctypes/doctypes-new.test.mjs +48 -6
- package/authoring/doctypes/enum/enum.doc.mjs +1 -1
- package/authoring/doctypes/enum/parse.d.mts +2 -2
- package/authoring/doctypes/enum/parse.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +4 -2
- package/authoring/doctypes/function/function.doc.mjs +7 -2
- package/authoring/doctypes/function/parse.d.mts +2 -2
- package/authoring/doctypes/function/parse.mjs +1 -1
- package/authoring/doctypes/function/type.ts +9 -4
- package/authoring/doctypes/hook/hook.doc.mjs +4 -0
- package/authoring/doctypes/hook/parse.d.mts +2 -2
- package/authoring/doctypes/hook/parse.mjs +1 -1
- package/authoring/doctypes/hook/type.ts +5 -4
- package/authoring/doctypes/legacy.d.mts +8 -6
- package/authoring/doctypes/legacy.mjs +5 -4
- package/authoring/doctypes/load-contract.test.mjs +233 -0
- package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
- package/authoring/doctypes/namespace/parse.d.mts +12 -0
- package/authoring/doctypes/namespace/parse.mjs +25 -0
- package/authoring/doctypes/namespace/parse.test.mjs +163 -0
- package/authoring/doctypes/namespace/type.ts +74 -0
- package/authoring/doctypes/parse.d.mts +22 -18
- package/authoring/doctypes/parse.mjs +22 -11
- package/authoring/doctypes/parse.test.mjs +77 -3
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +8 -5
- package/authoring/doctypes/reference/reference.doc.mjs +48 -6
- package/authoring/doctypes/reference/type.ts +70 -7
- package/authoring/doctypes/schema/parse.d.mts +2 -2
- package/authoring/doctypes/schema/parse.mjs +1 -1
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +4 -4
- package/authoring/doctypes/template/parse.d.mts +94 -1
- package/authoring/doctypes/template/parse.mjs +40 -2
- package/authoring/doctypes/template/parse.test.mjs +26 -2
- package/authoring/doctypes/template/template.doc.mjs +13 -3
- package/authoring/doctypes/template/type.ts +13 -2
- package/authoring/doctypes/theme/parse.d.mts +35 -0
- package/authoring/doctypes/theme/parse.mjs +76 -0
- package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
- package/authoring/doctypes/theme/theme.doc.mjs +79 -0
- package/authoring/doctypes/theme/type.ts +42 -0
- package/authoring/doctypes/types.ts +12 -10
- package/authoring/gap-report/gap-report.doc.d.mts +12 -0
- package/authoring/gap-report/gap-report.doc.mjs +183 -0
- package/authoring/gap-report/parse.d.mts +10 -10
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/identity/identity.doc.d.mts +9 -0
- package/authoring/identity/identity.doc.mjs +61 -0
- package/authoring/identity/type.ts +132 -0
- package/authoring/index.d.mts +3 -0
- package/authoring/index.d.ts +62 -17
- package/authoring/index.mjs +4 -1
- package/authoring/integration/integration.doc.mjs +15 -8
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/parse.test.mjs +10 -1
- package/authoring/integration/schema.d.mts +6 -4
- package/authoring/integration/schema.mjs +9 -3
- package/authoring/integration/type.ts +19 -8
- package/authoring/shadcn/receipt.d.mts +6 -6
- package/clients/cli/__tests__/cliManifest.test.ts +27 -29
- package/clients/cli/command-load-failure.test.mjs +83 -0
- package/clients/cli/command-result-coverage.test.mjs +7 -7
- 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 +24 -7
- package/clients/cli/commands/component.test.mjs +19 -0
- package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
- package/clients/cli/commands/detail-levels.test.mjs +2 -2
- package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
- package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
- package/clients/cli/commands/discover.doc.mjs +55 -9
- package/clients/cli/commands/discover.mjs +393 -118
- package/clients/cli/commands/discover.sources.test.mjs +267 -0
- package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
- package/clients/cli/commands/docs.doc.mjs +28 -6
- package/clients/cli/commands/docs.mjs +240 -26
- package/clients/cli/commands/docs.test.mjs +222 -1
- package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
- package/clients/cli/commands/doctor-integration.test.mjs +90 -8
- package/clients/cli/commands/doctor.doc.mjs +1 -1
- package/clients/cli/commands/doctor.mjs +59 -32
- package/clients/cli/commands/doctor.test.mjs +42 -0
- package/clients/cli/commands/gap-report.doc.mjs +17 -6
- package/clients/cli/commands/gap-report.test.mjs +72 -0
- package/clients/cli/commands/hook/index.mjs +7 -17
- package/clients/cli/commands/hook.doc.mjs +1 -1
- package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
- package/clients/cli/commands/init.doc.mjs +20 -9
- package/clients/cli/commands/init.flag-help.test.mjs +153 -0
- package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
- package/clients/cli/commands/integration-add.doc.mjs +32 -6
- package/clients/cli/commands/integration-authoring.test.mjs +13 -9
- package/clients/cli/commands/integration-pack.doc.mjs +1 -1
- package/clients/cli/commands/integration-real-world.test.mjs +3 -9
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/integration.mjs +1 -0
- package/clients/cli/commands/interactive-guard.test.mjs +101 -24
- package/clients/cli/commands/json-contract.test.mjs +33 -0
- package/clients/cli/commands/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 +702 -0
- package/clients/cli/commands/theme-add.doc.mjs +4 -3
- package/clients/cli/commands/theme-build.doc.mjs +8 -7
- package/clients/cli/commands/theme-list.doc.mjs +2 -2
- package/clients/cli/commands/theme-palette-generate.doc.mjs +9 -5
- package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
- package/clients/cli/commands/theme-palette.doc.mjs +1 -1
- package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
- package/clients/cli/commands/theme-targets.doc.mjs +1 -1
- package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
- package/clients/cli/commands/theme-template.doc.mjs +2 -2
- package/clients/cli/commands/theme.doc.mjs +1 -1
- package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
- package/clients/cli/commands/upgrade.doc.mjs +22 -10
- package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
- package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
- package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
- package/clients/cli/commands/upgrade.mjs +29 -7
- package/clients/cli/formatters/index.mjs +164 -1
- package/clients/cli/formatters/index.test.mjs +97 -0
- package/clients/cli/index.mjs +21 -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 +32 -6
- package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
- package/clients/cli/lib/exit-codes.test.mjs +90 -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 +69 -0
- package/clients/cli/lib/manifest.d.ts +2 -0
- package/clients/cli/lib/manifest.mjs +39 -10
- 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 +82 -12
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
- package/foundation/agent-docs/agent-docs.test.mjs +19 -1
- package/foundation/config/integration-debug.test.mjs +28 -3
- package/foundation/config/project-themes.test.mjs +11 -19
- package/foundation/config/project.d.mts +20 -11
- package/foundation/config/project.mjs +263 -91
- package/foundation/config/project.test.mjs +270 -21
- package/foundation/discovery/authoring-self-docs.d.mts +87 -0
- package/foundation/discovery/authoring-self-docs.mjs +237 -0
- package/foundation/discovery/authoring-self-docs.test.mjs +170 -0
- package/foundation/discovery/authoring-surface.d.mts +74 -0
- package/foundation/discovery/authoring-surface.mjs +525 -0
- package/foundation/discovery/authoring-surface.test.mjs +392 -0
- package/foundation/discovery/cli-self-docs.d.mts +119 -0
- package/foundation/discovery/cli-self-docs.mjs +490 -0
- package/foundation/discovery/cli-self-docs.test.mjs +375 -0
- package/foundation/discovery/component-discovery.d.mts +39 -1
- package/foundation/discovery/component-discovery.mjs +50 -1
- package/foundation/discovery/component-loader.d.mts +35 -38
- package/foundation/discovery/component-loader.mjs +53 -222
- package/foundation/discovery/docs-discovery.d.mts +119 -11
- package/foundation/discovery/docs-discovery.mjs +423 -108
- package/foundation/discovery/docs-discovery.test.mjs +365 -20
- package/foundation/discovery/docs-output-budget.d.mts +28 -0
- package/foundation/discovery/docs-output-budget.mjs +50 -0
- package/foundation/discovery/docs-section-key.d.mts +116 -0
- package/foundation/discovery/docs-section-key.mjs +322 -0
- package/foundation/discovery/docs-section-key.test.mjs +246 -0
- package/foundation/discovery/template-adapter.d.mts +113 -11
- package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
- package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
- package/foundation/discovery/template-adapter.mjs +775 -84
- 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 +1630 -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 +606 -0
- package/foundation/fs/file-protection.d.mts +33 -0
- package/foundation/fs/file-protection.mjs +825 -0
- package/foundation/fs/file-protection.test.mjs +250 -0
- package/foundation/fs/module-loader.d.mts +1 -0
- package/foundation/fs/module-loader.mjs +50 -1
- package/foundation/fs/module-loader.stdout.test.mjs +332 -0
- package/foundation/fs/path-safety.d.mts +3 -2
- package/foundation/fs/path-safety.mjs +49 -19
- package/foundation/fs/path-safety.test.mjs +50 -0
- package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
- package/foundation/identity/provider-identity.d.mts +90 -0
- package/foundation/identity/provider-identity.mjs +320 -0
- package/foundation/identity/provider-identity.test.mjs +254 -0
- package/foundation/identity/providers.d.mts +7 -0
- package/foundation/identity/providers.mjs +16 -0
- package/foundation/integrations/autolink.d.mts +58 -1
- package/foundation/integrations/autolink.mjs +143 -45
- package/foundation/integrations/autolink.test.mjs +1 -1
- package/foundation/integrations/cli-requirement.d.mts +45 -0
- package/foundation/integrations/cli-requirement.mjs +154 -0
- package/foundation/integrations/cli-requirement.test.mjs +84 -0
- package/foundation/integrations/contribution-fixes.d.mts +145 -0
- package/foundation/integrations/contribution-fixes.mjs +1284 -0
- package/foundation/integrations/contribution-inventory.d.mts +3 -2
- package/foundation/integrations/contribution-inventory.mjs +27 -24
- package/foundation/integrations/contribution-inventory.test.mjs +86 -27
- package/foundation/integrations/integration-warnings.d.mts +9 -2
- package/foundation/integrations/integration-warnings.mjs +52 -21
- package/foundation/integrations/integration-warnings.test.mjs +74 -1
- package/foundation/integrations/integrations.d.mts +63 -3
- package/foundation/integrations/integrations.mjs +122 -9
- package/foundation/integrations/integrations.test.mjs +415 -1
- package/foundation/integrations/provider-conflicts.test.mjs +125 -0
- package/foundation/integrations/provider-ledger.test.mjs +275 -0
- package/foundation/integrations/provider-resolution.d.mts +152 -0
- package/foundation/integrations/provider-resolution.mjs +576 -0
- package/foundation/integrations/provider-resolution.test.mjs +369 -0
- package/foundation/integrations/theme-descriptor.d.mts +8 -0
- package/foundation/integrations/theme-descriptor.mjs +44 -0
- package/foundation/integrations/validate-contributions.d.mts +2 -0
- package/foundation/integrations/validate-contributions.mjs +131 -29
- package/foundation/response/base.d.ts +8 -4
- package/foundation/response/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 +13 -4
- package/foundation/response/error-codes.mjs +8 -2
- package/foundation/response/error-codes.test.mjs +137 -10
- package/foundation/response/json-contract.test.mjs +57 -17
- package/foundation/response/json.d.mts +4 -2
- package/foundation/response/json.mjs +8 -10
- package/foundation/response/response-types.doc.d.mts +5 -1
- package/foundation/response/response-types.doc.mjs +46 -38
- package/foundation/response/response-types.doc.test.mjs +181 -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/browser.d.mts +3 -3
- package/foundation/xle/browser.mjs +3 -3
- package/foundation/xle/expand.d.mts +2 -0
- package/foundation/xle/expand.mjs +6 -5
- package/foundation/xle/expand.test.mjs +54 -0
- package/foundation/xle/parse.mjs +1 -1
- package/foundation/xle/print.mjs +2 -2
- package/foundation/xle/splice.mjs +1 -1
- package/foundation/xle/xle.test.mjs +13 -0
- package/package.json +10 -11
- package/api/layout/_adapter.d.mts +0 -34
- package/api/layout/_adapter.mjs +0 -133
- package/api/layout/check/check.d.mts +0 -16
- package/api/layout/check/check.mjs +0 -40
- package/api/layout/expand/expand.d.mts +0 -22
- package/api/layout/expand/expand.mjs +0 -153
- package/api/layout/grammar/grammar.d.mts +0 -13
- package/api/layout/grammar/grammar.mjs +0 -86
- package/api/layout/layout.d.mts +0 -6
- package/api/layout/layout.mjs +0 -17
- package/api/layout/layout.test.mjs +0 -297
- package/api/layout/layout.type.d.mts +0 -89
- package/api/layout/layout.type.mjs +0 -103
- package/api/layout/layoutCheck.doc.d.mts +0 -11
- package/api/layout/layoutCheck.doc.mjs +0 -84
- package/api/layout/layoutExpand.doc.d.mts +0 -11
- package/api/layout/layoutExpand.doc.mjs +0 -106
- package/api/layout/layoutGrammar.doc.d.mts +0 -11
- package/api/layout/layoutGrammar.doc.mjs +0 -56
- package/assets/templates/themes/manifest.json +0 -95
- package/clients/cli/commands/layout-check.doc.mjs +0 -54
- package/clients/cli/commands/layout-expand.doc.mjs +0 -66
- package/clients/cli/commands/layout-grammar.doc.mjs +0 -30
- package/clients/cli/commands/layout.doc.mjs +0 -34
- package/clients/cli/commands/layout.error-codes.test.mjs +0 -66
- package/clients/cli/commands/layout.exit-parity.test.mjs +0 -41
- package/clients/cli/commands/layout.mjs +0 -263
- 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
|
@@ -0,0 +1,876 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The docs tree: one home for every doc that a namespace places or
|
|
5
|
+
* adopts (spec:AST-046).
|
|
6
|
+
*
|
|
7
|
+
* @input Namespace docs, guides that name a parent with `placement`, and typed
|
|
8
|
+
* docs that belong to a discovery group (a CLI typed doc's `namespace`).
|
|
9
|
+
* @output {@link buildDocsTree}: every node by route, each with one parent and
|
|
10
|
+
* ordered children per slot, plus one diagnostic for each placement that
|
|
11
|
+
* failed. {@link loadDocsTree} builds the CLI's own tree once per process.
|
|
12
|
+
* @position Between discovery and the readers: `astryx docs <route>`,
|
|
13
|
+
* `astryx doctor`, and the docsite build all read this tree. The CLI's docs
|
|
14
|
+
* and each integration's have a home here, and a flat topic's home is the
|
|
15
|
+
* generated Unorganized level.
|
|
16
|
+
* A namespace never scans files and never lists its children: a child names
|
|
17
|
+
* its parent, or a namespace adopts a discovery group.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import * as fs from 'node:fs';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
import {CLI_ROOT} from '../fs/paths.mjs';
|
|
23
|
+
import {loadCliSelfDocs} from '../discovery/cli-self-docs.mjs';
|
|
24
|
+
import {routeSegment} from '../discovery/docs-section-key.mjs';
|
|
25
|
+
import {diagnostic, sortDiagnostics} from './diagnostics.mjs';
|
|
26
|
+
import {readDocView} from './read.mjs';
|
|
27
|
+
import {packageSource} from './source.mjs';
|
|
28
|
+
import {createDocId} from '../identity/provider-identity.mjs';
|
|
29
|
+
import {CLI_PROVIDER_ID} from '../identity/providers.mjs';
|
|
30
|
+
|
|
31
|
+
export {routeSegment};
|
|
32
|
+
|
|
33
|
+
/** Where the CLI keeps the docs that only the tree reads. */
|
|
34
|
+
export const TREE_DOCS_DIR = path.join(CLI_ROOT, 'assets', 'docs', 'tree');
|
|
35
|
+
|
|
36
|
+
/** The package that owns the CLI's own docs. */
|
|
37
|
+
const CLI_PROVIDER = '@astryxdesign/cli';
|
|
38
|
+
|
|
39
|
+
/** One route segment: lowercase letters and digits joined by single hyphens. */
|
|
40
|
+
export const ROUTE_SEGMENT_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The generated level that `groupBy: 'kind'` makes for each kind: its route
|
|
44
|
+
* segment, title, and summary.
|
|
45
|
+
* @type {Readonly<Record<string, {segment: string, title: string, summary: string}>>}
|
|
46
|
+
*/
|
|
47
|
+
export const KIND_GROUPS = Object.freeze({
|
|
48
|
+
command: {
|
|
49
|
+
segment: 'commands',
|
|
50
|
+
title: 'Commands',
|
|
51
|
+
summary: 'Every command and subcommand.',
|
|
52
|
+
},
|
|
53
|
+
function: {
|
|
54
|
+
segment: 'functions',
|
|
55
|
+
title: 'Functions',
|
|
56
|
+
summary: 'Every function: its signature, parameters, returns, and errors.',
|
|
57
|
+
},
|
|
58
|
+
schema: {
|
|
59
|
+
segment: 'schemas',
|
|
60
|
+
title: 'Schemas',
|
|
61
|
+
summary: 'Every shape the CLI reads or returns, field by field.',
|
|
62
|
+
},
|
|
63
|
+
enum: {
|
|
64
|
+
segment: 'enums',
|
|
65
|
+
title: 'Enums',
|
|
66
|
+
summary:
|
|
67
|
+
'Every fixed list of values, such as error codes and response types.',
|
|
68
|
+
},
|
|
69
|
+
generic: {segment: 'guides', title: 'Guides', summary: 'Every guide.'},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @typedef {import('../../authoring/doctypes/namespace/type').NamespaceDoc} NamespaceDoc
|
|
74
|
+
* @typedef {import('../../authoring/doctypes/base/type').DocPlacement} DocPlacement
|
|
75
|
+
* @typedef {import('./diagnostics.mjs').CompilerDiagnostic} CompilerDiagnostic
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @typedef {object} TreeNamespaceInput
|
|
80
|
+
* @property {string} provider the package that owns the namespace
|
|
81
|
+
* @property {string} providerId the provider's ProviderId (its manifest
|
|
82
|
+
* `providerId`, else its package name); node ids are built from it
|
|
83
|
+
* @property {number} [rank] which provider wins a contested route: the CLI's
|
|
84
|
+
* own docs are 0, then each integration in configured order
|
|
85
|
+
* @property {string} source `<package>/<path>` of its file
|
|
86
|
+
* @property {NamespaceDoc} doc
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @typedef {object} TreeDocInput
|
|
91
|
+
* @property {string} provider the package that authored the doc
|
|
92
|
+
* @property {string} providerId the provider's ProviderId (its manifest
|
|
93
|
+
* `providerId`, else its package name); node ids are built from it
|
|
94
|
+
* @property {number} [rank] which provider wins a contested route: the CLI's
|
|
95
|
+
* own docs are 0, then each integration in configured order
|
|
96
|
+
* @property {string} source
|
|
97
|
+
* @property {import('../../authoring/doctypes/base/type').AuthoredDocKind} kind
|
|
98
|
+
* the authored kind: `generic`, `command`, `function`, `schema`, or `enum`
|
|
99
|
+
* @property {string} name the doc's stable name
|
|
100
|
+
* @property {string} title
|
|
101
|
+
* @property {string} summary
|
|
102
|
+
* @property {string | null} group the discovery group adoption reads, or null
|
|
103
|
+
* @property {DocPlacement | undefined} placement
|
|
104
|
+
* @property {any} [ref] what a reader needs to open the doc, carried as given
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @typedef {object} TreeSlot
|
|
109
|
+
* @property {string} name
|
|
110
|
+
* @property {string} title
|
|
111
|
+
* @property {string[]} children child routes, in reading order
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A flat topic: a reference topic that no namespace places. The tree gives it
|
|
116
|
+
* a home in the generated Unorganized level, under its own name.
|
|
117
|
+
* @typedef {object} TreeTopicInput
|
|
118
|
+
* @property {string} provider the package that owns the topic
|
|
119
|
+
* @property {string} providerId the provider's ProviderId
|
|
120
|
+
* @property {string} name the topic's name, which stays its route
|
|
121
|
+
* @property {string} title
|
|
122
|
+
* @property {string} summary
|
|
123
|
+
* @property {string} source where the topic comes from, for diagnostics
|
|
124
|
+
* @property {string[]} [aliases] every other name the topic answers to: the
|
|
125
|
+
* topics it replaced, directly or through a chain
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
/** The route of the generated level that holds every flat topic. */
|
|
129
|
+
export const UNORGANIZED = 'unorganized';
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @typedef {object} TreeNode
|
|
133
|
+
* @property {string | null} id the doc's DocId, built from its provider's
|
|
134
|
+
* ProviderId, kind, and name: stable when the route moves; null on a
|
|
135
|
+
* generated level, which has no authored doc
|
|
136
|
+
* @property {string} route
|
|
137
|
+
* @property {string} kind `namespace` or the doc's authored kind
|
|
138
|
+
* @property {string} provider the package that owns it
|
|
139
|
+
* @property {string} providerId its provider's ProviderId
|
|
140
|
+
* @property {string} name
|
|
141
|
+
* @property {string} title
|
|
142
|
+
* @property {string} summary
|
|
143
|
+
* @property {string | null} parent the parent's route; null at the top
|
|
144
|
+
* @property {string | null} slot the parent slot this node sits in
|
|
145
|
+
* @property {number | null} order
|
|
146
|
+
* @property {boolean} generated made by the compiler (a `groupBy: 'kind'`
|
|
147
|
+
* level, or the Unorganized level), not authored
|
|
148
|
+
* @property {TreeSlot[]} slots a namespace's slots; empty for a leaf
|
|
149
|
+
* @property {string} source
|
|
150
|
+
* @property {any} [ref]
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @typedef {object} DocsTree
|
|
155
|
+
* @property {Map<string, TreeNode>} nodes by route, in route order
|
|
156
|
+
* @property {CompilerDiagnostic[]} diagnostics sorted
|
|
157
|
+
* @property {(route: string) => TreeNode | undefined} get
|
|
158
|
+
* @property {(route: string) => TreeNode | undefined} getFolded the node at a
|
|
159
|
+
* route compared without case, as topic names are
|
|
160
|
+
* @property {() => TreeNode[]} roots the namespaces with no parent
|
|
161
|
+
* @property {(node: TreeNode) => TreeNode[]} ancestors top first, not the node
|
|
162
|
+
*/
|
|
163
|
+
|
|
164
|
+
/** @param {string} a @param {string} b */
|
|
165
|
+
const byText = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The namespace a `placement.parent` names: `namespace:<name>` in the doc's own
|
|
169
|
+
* package, or `<package>/namespace/<name>` spelled out. In phase 1 a parent
|
|
170
|
+
* must belong to the doc's own package.
|
|
171
|
+
* @param {string} parent
|
|
172
|
+
* @param {string} provider
|
|
173
|
+
* @param {Map<string, TreeNamespaceInput>} declared by `provider\0name`
|
|
174
|
+
* @returns {{key: string} | {error: string}}
|
|
175
|
+
*/
|
|
176
|
+
function resolveParent(parent, provider, declared) {
|
|
177
|
+
let owner = provider;
|
|
178
|
+
let name;
|
|
179
|
+
const short = /^namespace:(.+)$/u.exec(parent);
|
|
180
|
+
const qualified = /^(.+)\/namespace\/([^/]+)$/u.exec(parent);
|
|
181
|
+
if (short) {
|
|
182
|
+
name = short[1];
|
|
183
|
+
} else if (qualified) {
|
|
184
|
+
[, owner, name] = qualified;
|
|
185
|
+
} else {
|
|
186
|
+
return {
|
|
187
|
+
error: `placement.parent "${parent}" is not a namespace reference. Write "namespace:<name>".`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (owner !== provider) {
|
|
191
|
+
return {
|
|
192
|
+
error: `placement.parent "${parent}" belongs to ${owner}. A doc can only be placed in a namespace of its own package (${provider}).`,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const key = `${owner}\u0000${name}`;
|
|
196
|
+
if (!declared.has(key)) {
|
|
197
|
+
return {
|
|
198
|
+
error: `placement.parent "${parent}" names no namespace; ${provider} declares ${
|
|
199
|
+
[...declared.values()]
|
|
200
|
+
.filter(ns => ns.provider === provider)
|
|
201
|
+
.map(ns => `"${ns.doc.name}"`)
|
|
202
|
+
.sort(byText)
|
|
203
|
+
.join(', ') || 'none'
|
|
204
|
+
}.`,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return {key};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Build the tree. Pure: the same inputs give the same tree, whatever order
|
|
212
|
+
* they arrive in.
|
|
213
|
+
*
|
|
214
|
+
* A doc's home is decided once, in this order: its explicit `placement`, then
|
|
215
|
+
* the one adoption rule in its package that matches its group and kind. A
|
|
216
|
+
* placement that fails withdraws the doc; it never falls back to adoption. A
|
|
217
|
+
* doc with neither is a flat topic: it keeps its flat name as its route, and its
|
|
218
|
+
* home is the generated Unorganized level. The CLI keeps its own routes: an
|
|
219
|
+
* integration's node that would take one is withdrawn with a diagnostic.
|
|
220
|
+
*
|
|
221
|
+
* @param {{namespaces: TreeNamespaceInput[], docs: TreeDocInput[], topics?: TreeTopicInput[]}} inputs
|
|
222
|
+
* @returns {DocsTree}
|
|
223
|
+
*/
|
|
224
|
+
export function buildDocsTree({namespaces, docs, topics = []}) {
|
|
225
|
+
/** @type {CompilerDiagnostic[]} */
|
|
226
|
+
const diagnostics = [];
|
|
227
|
+
/** @param {string} code @param {{provider: string, source: string}} at @param {string} message @param {string} [field] */
|
|
228
|
+
const report = (code, at, message, field) =>
|
|
229
|
+
diagnostics.push(
|
|
230
|
+
diagnostic(code, {
|
|
231
|
+
provider: at.provider,
|
|
232
|
+
source: at.source,
|
|
233
|
+
message,
|
|
234
|
+
...(field ? {field} : {}),
|
|
235
|
+
}),
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
// Routes the CLI's own docs keep (spec:AST-046 FR11): the name of each of
|
|
239
|
+
// its flat topics, and the generated Unorganized level. Its namespaces keep
|
|
240
|
+
// theirs by rank, because they go into the tree first. Routes compare
|
|
241
|
+
// without case, as topic names do, so `CLI` claims `cli`.
|
|
242
|
+
const cliRoutes = new Set(topics.length > 0 ? [UNORGANIZED] : []);
|
|
243
|
+
for (const topic of topics) {
|
|
244
|
+
if (topic.provider === CLI_PROVIDER) cliRoutes.add(topic.name.toLowerCase());
|
|
245
|
+
}
|
|
246
|
+
// Every other name a topic answers to (the topics it replaced, directly or
|
|
247
|
+
// through a chain) is that topic's route too: `astryx docs <name>` opens the
|
|
248
|
+
// replacement, so no other doc can hold it.
|
|
249
|
+
/** @type {Map<string, TreeTopicInput>} */
|
|
250
|
+
const aliasRoutes = new Map();
|
|
251
|
+
for (const topic of topics) {
|
|
252
|
+
for (const alias of topic.aliases ?? []) {
|
|
253
|
+
aliasRoutes.set(alias.toLowerCase(), topic);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Namespaces by package and name.
|
|
258
|
+
/** @type {Map<string, TreeNamespaceInput>} */
|
|
259
|
+
const declared = new Map();
|
|
260
|
+
const sortedNamespaces = [...namespaces].sort(
|
|
261
|
+
(a, b) =>
|
|
262
|
+
(a.rank ?? 0) - (b.rank ?? 0) ||
|
|
263
|
+
byText(a.provider, b.provider) ||
|
|
264
|
+
byText(a.doc.name, b.doc.name) ||
|
|
265
|
+
byText(a.source, b.source),
|
|
266
|
+
);
|
|
267
|
+
for (const input of sortedNamespaces) {
|
|
268
|
+
const {name} = input.doc;
|
|
269
|
+
if (!ROUTE_SEGMENT_RE.test(name)) {
|
|
270
|
+
report(
|
|
271
|
+
'invalid_namespace',
|
|
272
|
+
input,
|
|
273
|
+
`Namespace "${name}" is not a route segment. Use lowercase letters and digits joined by single hyphens.`,
|
|
274
|
+
'name',
|
|
275
|
+
);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
const key = `${input.provider}\u0000${name}`;
|
|
279
|
+
const first = declared.get(key);
|
|
280
|
+
if (first) {
|
|
281
|
+
report(
|
|
282
|
+
'invalid_namespace',
|
|
283
|
+
input,
|
|
284
|
+
`Namespace "${name}" is declared twice in ${input.provider}: ${first.source} and ${input.source}.`,
|
|
285
|
+
'name',
|
|
286
|
+
);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
declared.set(key, input);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Each namespace's parent, checked against the parent's slots.
|
|
293
|
+
/** @type {Map<string, {parentKey: string, slot: string, order: number | null} | null>} */
|
|
294
|
+
const parentOf = new Map();
|
|
295
|
+
for (const [key, input] of declared) {
|
|
296
|
+
const {placement} = input.doc;
|
|
297
|
+
if (placement == null) {
|
|
298
|
+
parentOf.set(key, null);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
const home = checkPlacement(placement, 'namespace', input, declared);
|
|
302
|
+
if ('error' in home) {
|
|
303
|
+
report('invalid_placement', input, home.error, 'placement');
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
parentOf.set(key, {
|
|
307
|
+
parentKey: home.key,
|
|
308
|
+
slot: home.slot,
|
|
309
|
+
order: placement.order ?? null,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Routes, top-down. A cycle, or an ancestor that was withdrawn, leaves a
|
|
314
|
+
// namespace (and everything under it) out of the tree.
|
|
315
|
+
/** @type {Map<string, string | null>} */
|
|
316
|
+
const routeOf = new Map();
|
|
317
|
+
/** @param {string} key @param {Set<string>} seen @returns {string | null} */
|
|
318
|
+
const routeFor = (key, seen) => {
|
|
319
|
+
if (routeOf.has(key))
|
|
320
|
+
return /** @type {string | null} */ (routeOf.get(key));
|
|
321
|
+
if (!parentOf.has(key) || seen.has(key)) return null;
|
|
322
|
+
seen.add(key);
|
|
323
|
+
const home = parentOf.get(key);
|
|
324
|
+
const name = /** @type {TreeNamespaceInput} */ (declared.get(key)).doc.name;
|
|
325
|
+
const parentRoute = home == null ? '' : routeFor(home.parentKey, seen);
|
|
326
|
+
const route =
|
|
327
|
+
parentRoute == null
|
|
328
|
+
? null
|
|
329
|
+
: parentRoute === ''
|
|
330
|
+
? name
|
|
331
|
+
: `${parentRoute}/${name}`;
|
|
332
|
+
routeOf.set(key, route);
|
|
333
|
+
return route;
|
|
334
|
+
};
|
|
335
|
+
for (const [key, input] of declared) {
|
|
336
|
+
if (routeFor(key, new Set()) == null && parentOf.has(key)) {
|
|
337
|
+
report(
|
|
338
|
+
'invalid_placement',
|
|
339
|
+
input,
|
|
340
|
+
`Namespace "${input.doc.name}" has no route: its placement forms a cycle, or a namespace above it was withdrawn.`,
|
|
341
|
+
'placement',
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** @type {Map<string, TreeNode>} */
|
|
347
|
+
const nodes = new Map();
|
|
348
|
+
/** @type {Map<string, TreeNode>} nodes by route, compared without case */
|
|
349
|
+
const byFoldedRoute = new Map();
|
|
350
|
+
/** @param {TreeNode} node */
|
|
351
|
+
const nodeLabel = node => node.id ?? `the generated level "${node.route}"`;
|
|
352
|
+
/** @param {TreeNode} node @param {{provider: string, source: string}} at */
|
|
353
|
+
const addNode = (node, at) => {
|
|
354
|
+
const folded = node.route.toLowerCase();
|
|
355
|
+
if (node.provider !== CLI_PROVIDER && cliRoutes.has(folded)) {
|
|
356
|
+
report(
|
|
357
|
+
'duplicate_route',
|
|
358
|
+
at,
|
|
359
|
+
`${nodeLabel(node)} takes the route "${node.route}", which the CLI's own docs keep. Rename it.`,
|
|
360
|
+
);
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
const alias = aliasRoutes.get(folded);
|
|
364
|
+
if (
|
|
365
|
+
alias != null &&
|
|
366
|
+
node.provider !== CLI_PROVIDER &&
|
|
367
|
+
node.ref?.flatTopic !== alias.name
|
|
368
|
+
) {
|
|
369
|
+
report(
|
|
370
|
+
'duplicate_route',
|
|
371
|
+
at,
|
|
372
|
+
`${nodeLabel(node)} takes the route "${node.route}", which the topic "${alias.name}" also answers to, because it replaced a topic of that name. Rename it.`,
|
|
373
|
+
);
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
const taken = byFoldedRoute.get(folded);
|
|
377
|
+
if (taken) {
|
|
378
|
+
report(
|
|
379
|
+
'duplicate_route',
|
|
380
|
+
at,
|
|
381
|
+
`${nodeLabel(node)} and ${nodeLabel(taken)} both have the route "${node.route}". Rename or move one of them.`,
|
|
382
|
+
);
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
nodes.set(node.route, node);
|
|
386
|
+
byFoldedRoute.set(folded, node);
|
|
387
|
+
return true;
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// Parents before children, so a namespace placed in a withdrawn namespace
|
|
391
|
+
// is withdrawn before anything is placed in it.
|
|
392
|
+
const parentsFirst = [...declared].sort(
|
|
393
|
+
([a], [b]) =>
|
|
394
|
+
String(routeOf.get(a) ?? '').split('/').length -
|
|
395
|
+
String(routeOf.get(b) ?? '').split('/').length,
|
|
396
|
+
);
|
|
397
|
+
for (const [key, input] of parentsFirst) {
|
|
398
|
+
const route = routeOf.get(key);
|
|
399
|
+
if (route == null) continue;
|
|
400
|
+
const home = parentOf.get(key);
|
|
401
|
+
if (home != null && routeOf.get(home.parentKey) == null) {
|
|
402
|
+
routeOf.set(key, null);
|
|
403
|
+
report(
|
|
404
|
+
'invalid_placement',
|
|
405
|
+
input,
|
|
406
|
+
`Namespace "${input.doc.name}" has no route: the namespace it is placed in was withdrawn.`,
|
|
407
|
+
'placement',
|
|
408
|
+
);
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
const parentRoute =
|
|
412
|
+
home == null ? null : /** @type {string} */ (routeOf.get(home.parentKey));
|
|
413
|
+
const added = addNode(
|
|
414
|
+
{
|
|
415
|
+
id: createDocId(input.providerId, 'namespace', input.doc.name),
|
|
416
|
+
route,
|
|
417
|
+
kind: 'namespace',
|
|
418
|
+
provider: input.provider,
|
|
419
|
+
providerId: input.providerId,
|
|
420
|
+
name: input.doc.name,
|
|
421
|
+
title: input.doc.title,
|
|
422
|
+
summary: input.doc.summary,
|
|
423
|
+
parent: parentRoute,
|
|
424
|
+
slot: home?.slot ?? null,
|
|
425
|
+
order: home?.order ?? null,
|
|
426
|
+
generated: false,
|
|
427
|
+
slots: Object.entries(input.doc.slots).map(([name, slot]) => ({
|
|
428
|
+
name,
|
|
429
|
+
title: slot.title,
|
|
430
|
+
children: [],
|
|
431
|
+
})),
|
|
432
|
+
source: input.source,
|
|
433
|
+
},
|
|
434
|
+
input,
|
|
435
|
+
);
|
|
436
|
+
// A withdrawn namespace has no route, so a namespace placed in it is
|
|
437
|
+
// withdrawn too, and a doc placed in it says so.
|
|
438
|
+
if (!added) routeOf.set(key, null);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Docs: explicit placement, else one adoption rule, else no home.
|
|
442
|
+
const sortedDocs = [...docs].sort(
|
|
443
|
+
(a, b) =>
|
|
444
|
+
(a.rank ?? 0) - (b.rank ?? 0) ||
|
|
445
|
+
byText(a.provider, b.provider) ||
|
|
446
|
+
byText(a.kind, b.kind) ||
|
|
447
|
+
byText(a.name, b.name) ||
|
|
448
|
+
byText(a.source, b.source),
|
|
449
|
+
);
|
|
450
|
+
for (const doc of sortedDocs) {
|
|
451
|
+
/** @type {{parentRoute: string, slot: string, order: number | null} | null} */
|
|
452
|
+
let home = null;
|
|
453
|
+
if (doc.placement != null) {
|
|
454
|
+
const placed = checkPlacement(doc.placement, doc.kind, doc, declared);
|
|
455
|
+
if ('error' in placed) {
|
|
456
|
+
report('invalid_placement', doc, placed.error, 'placement');
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const parentRoute = routeOf.get(placed.key);
|
|
460
|
+
if (parentRoute == null) {
|
|
461
|
+
report(
|
|
462
|
+
'invalid_placement',
|
|
463
|
+
doc,
|
|
464
|
+
`placement.parent "${doc.placement.parent}" names a namespace that has no route.`,
|
|
465
|
+
'placement',
|
|
466
|
+
);
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
home = {
|
|
470
|
+
parentRoute,
|
|
471
|
+
slot: placed.slot,
|
|
472
|
+
order: doc.placement.order ?? null,
|
|
473
|
+
};
|
|
474
|
+
} else if (doc.group != null) {
|
|
475
|
+
const matches = adoptionsFor(doc, declared, routeOf);
|
|
476
|
+
if (matches.length > 1) {
|
|
477
|
+
report(
|
|
478
|
+
'overlapping_adoption',
|
|
479
|
+
doc,
|
|
480
|
+
`${doc.provider}/${doc.kind}/${doc.name} is adopted by ${matches
|
|
481
|
+
.map(m => `"${m.namespace.doc.name}"`)
|
|
482
|
+
.join(' and ')}; exactly one namespace may adopt a doc.`,
|
|
483
|
+
);
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (matches.length === 1) {
|
|
487
|
+
const [{key, rule, namespace}] = matches;
|
|
488
|
+
const nsRoute = /** @type {string} */ (routeOf.get(key));
|
|
489
|
+
if (rule.groupBy === 'kind') {
|
|
490
|
+
const group = KIND_GROUPS[doc.kind] ?? {
|
|
491
|
+
segment: `${routeSegment(doc.kind)}s`,
|
|
492
|
+
title: doc.kind,
|
|
493
|
+
summary: `Every ${doc.kind} doc.`,
|
|
494
|
+
};
|
|
495
|
+
const groupRoute = `${nsRoute}/${group.segment}`;
|
|
496
|
+
if (!nodes.has(groupRoute)) {
|
|
497
|
+
const kinds = rule.source.kinds ?? [];
|
|
498
|
+
addNode(
|
|
499
|
+
{
|
|
500
|
+
id: null,
|
|
501
|
+
route: groupRoute,
|
|
502
|
+
kind: 'namespace',
|
|
503
|
+
provider: namespace.provider,
|
|
504
|
+
providerId: namespace.providerId,
|
|
505
|
+
name: group.segment,
|
|
506
|
+
title: group.title,
|
|
507
|
+
summary: group.summary,
|
|
508
|
+
parent: nsRoute,
|
|
509
|
+
slot: rule.into,
|
|
510
|
+
order: kinds.includes(/** @type {any} */ (doc.kind))
|
|
511
|
+
? kinds.indexOf(/** @type {any} */ (doc.kind))
|
|
512
|
+
: null,
|
|
513
|
+
generated: true,
|
|
514
|
+
slots: [{name: 'items', title: group.title, children: []}],
|
|
515
|
+
source: namespace.source,
|
|
516
|
+
},
|
|
517
|
+
namespace,
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
const groupNode = nodes.get(groupRoute);
|
|
521
|
+
if (!groupNode?.generated) continue;
|
|
522
|
+
home = {parentRoute: groupRoute, slot: 'items', order: null};
|
|
523
|
+
} else {
|
|
524
|
+
home = {parentRoute: nsRoute, slot: rule.into, order: null};
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
if (home == null) continue;
|
|
529
|
+
const segment = routeSegment(doc.name);
|
|
530
|
+
if (segment === '') {
|
|
531
|
+
report(
|
|
532
|
+
'invalid_placement',
|
|
533
|
+
doc,
|
|
534
|
+
`${doc.provider}/${doc.kind}/${doc.name} has no route segment: its name holds no letters or digits.`,
|
|
535
|
+
'name',
|
|
536
|
+
);
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
addNode(
|
|
540
|
+
{
|
|
541
|
+
id: createDocId(doc.providerId, doc.kind, doc.name),
|
|
542
|
+
route: `${home.parentRoute}/${segment}`,
|
|
543
|
+
kind: doc.kind,
|
|
544
|
+
provider: doc.provider,
|
|
545
|
+
providerId: doc.providerId,
|
|
546
|
+
name: doc.name,
|
|
547
|
+
title: doc.title,
|
|
548
|
+
summary: doc.summary,
|
|
549
|
+
parent: home.parentRoute,
|
|
550
|
+
slot: home.slot,
|
|
551
|
+
order: home.order,
|
|
552
|
+
generated: false,
|
|
553
|
+
slots: [],
|
|
554
|
+
source: doc.source,
|
|
555
|
+
...(doc.ref === undefined ? {} : {ref: doc.ref}),
|
|
556
|
+
},
|
|
557
|
+
doc,
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// The generated Unorganized level (spec:AST-046 FR12): every flat topic sits
|
|
562
|
+
// here, in the order the topic list reads, so every doc has a home in the
|
|
563
|
+
// tree. A topic keeps its own name as its route.
|
|
564
|
+
if (topics.length > 0) {
|
|
565
|
+
const home = {
|
|
566
|
+
id: null,
|
|
567
|
+
route: UNORGANIZED,
|
|
568
|
+
kind: 'namespace',
|
|
569
|
+
provider: CLI_PROVIDER,
|
|
570
|
+
providerId: CLI_PROVIDER_ID,
|
|
571
|
+
name: UNORGANIZED,
|
|
572
|
+
title: 'Unorganized',
|
|
573
|
+
summary:
|
|
574
|
+
'Every topic that no section places yet. Each keeps its own name; open one by it.',
|
|
575
|
+
parent: null,
|
|
576
|
+
slot: null,
|
|
577
|
+
order: null,
|
|
578
|
+
generated: true,
|
|
579
|
+
slots: [{name: 'topics', title: 'Topics', children: []}],
|
|
580
|
+
source: 'generated',
|
|
581
|
+
};
|
|
582
|
+
if (addNode(home, {provider: CLI_PROVIDER, source: 'generated'})) {
|
|
583
|
+
topics.forEach((topic, i) => {
|
|
584
|
+
addNode(
|
|
585
|
+
{
|
|
586
|
+
id: createDocId(topic.providerId, 'generic', topic.name),
|
|
587
|
+
route: topic.name,
|
|
588
|
+
kind: 'generic',
|
|
589
|
+
provider: topic.provider,
|
|
590
|
+
providerId: topic.providerId,
|
|
591
|
+
name: topic.name,
|
|
592
|
+
title: topic.title,
|
|
593
|
+
summary: topic.summary,
|
|
594
|
+
parent: UNORGANIZED,
|
|
595
|
+
slot: 'topics',
|
|
596
|
+
order: i,
|
|
597
|
+
generated: false,
|
|
598
|
+
slots: [],
|
|
599
|
+
source: topic.source,
|
|
600
|
+
ref: {flatTopic: topic.name},
|
|
601
|
+
},
|
|
602
|
+
topic,
|
|
603
|
+
);
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Children, per slot, in reading order: order, then title, then id.
|
|
609
|
+
for (const node of nodes.values()) {
|
|
610
|
+
if (node.parent == null) continue;
|
|
611
|
+
const parent = nodes.get(node.parent);
|
|
612
|
+
parent?.slots
|
|
613
|
+
.find(slot => slot.name === node.slot)
|
|
614
|
+
?.children.push(node.route);
|
|
615
|
+
}
|
|
616
|
+
for (const node of nodes.values()) {
|
|
617
|
+
for (const slot of node.slots) {
|
|
618
|
+
slot.children.sort((a, b) => {
|
|
619
|
+
const x = /** @type {TreeNode} */ (nodes.get(a));
|
|
620
|
+
const y = /** @type {TreeNode} */ (nodes.get(b));
|
|
621
|
+
return (
|
|
622
|
+
(x.order ?? Infinity) - (y.order ?? Infinity) ||
|
|
623
|
+
byText(x.title.toLowerCase(), y.title.toLowerCase()) ||
|
|
624
|
+
byText(x.id ?? x.route, y.id ?? y.route)
|
|
625
|
+
);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// A topic that answers, through `replaces`, to a route the CLI's own docs
|
|
631
|
+
// keep cannot have it: the CLI's doc opens there. Say so, against the topic.
|
|
632
|
+
for (const topic of topics) {
|
|
633
|
+
if (topic.provider === CLI_PROVIDER) continue;
|
|
634
|
+
for (const alias of topic.aliases ?? []) {
|
|
635
|
+
const holder = byFoldedRoute.get(alias.toLowerCase());
|
|
636
|
+
if (holder != null && holder.provider === CLI_PROVIDER) {
|
|
637
|
+
report(
|
|
638
|
+
'duplicate_route',
|
|
639
|
+
topic,
|
|
640
|
+
`The topic "${topic.name}" answers to "${alias}" through replaces, but the CLI's own docs keep that route, so \`astryx docs ${alias}\` opens theirs. Drop that replacement.`,
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const sorted = new Map([...nodes.entries()].sort(([a], [b]) => byText(a, b)));
|
|
647
|
+
return {
|
|
648
|
+
nodes: sorted,
|
|
649
|
+
diagnostics: sortDiagnostics(diagnostics),
|
|
650
|
+
get: route => sorted.get(route),
|
|
651
|
+
getFolded: route => byFoldedRoute.get(String(route).toLowerCase()),
|
|
652
|
+
roots: () => [...sorted.values()].filter(node => node.parent == null),
|
|
653
|
+
ancestors: node => {
|
|
654
|
+
/** @type {TreeNode[]} */
|
|
655
|
+
const chain = [];
|
|
656
|
+
let parent = node.parent == null ? undefined : sorted.get(node.parent);
|
|
657
|
+
while (parent) {
|
|
658
|
+
chain.unshift(parent);
|
|
659
|
+
parent = parent.parent == null ? undefined : sorted.get(parent.parent);
|
|
660
|
+
}
|
|
661
|
+
return chain;
|
|
662
|
+
},
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Check a placement against the namespace it names: the namespace exists in
|
|
668
|
+
* the doc's own package, the slot is one it declares, and the slot accepts the
|
|
669
|
+
* doc's kind.
|
|
670
|
+
* @param {DocPlacement} placement
|
|
671
|
+
* @param {string} kind
|
|
672
|
+
* @param {{provider: string}} at
|
|
673
|
+
* @param {Map<string, TreeNamespaceInput>} declared
|
|
674
|
+
* @returns {{key: string, slot: string} | {error: string}}
|
|
675
|
+
*/
|
|
676
|
+
function checkPlacement(placement, kind, at, declared) {
|
|
677
|
+
const target = resolveParent(placement.parent, at.provider, declared);
|
|
678
|
+
if ('error' in target) return target;
|
|
679
|
+
const parent = /** @type {TreeNamespaceInput} */ (declared.get(target.key));
|
|
680
|
+
const slotNames = Object.keys(parent.doc.slots);
|
|
681
|
+
const slot = placement.slot ?? (slotNames.length === 1 ? slotNames[0] : null);
|
|
682
|
+
if (slot == null) {
|
|
683
|
+
return {
|
|
684
|
+
error: `placement names no slot, and namespace "${parent.doc.name}" has ${slotNames.length} (${slotNames.join(', ')}). Name one with placement.slot.`,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
const declaredSlot = parent.doc.slots[slot];
|
|
688
|
+
if (declaredSlot == null) {
|
|
689
|
+
return {
|
|
690
|
+
error: `placement.slot "${slot}" is not a slot of namespace "${parent.doc.name}"; it declares ${slotNames.join(', ')}.`,
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
if (!declaredSlot.accepts.kinds.includes(/** @type {any} */ (kind))) {
|
|
694
|
+
return {
|
|
695
|
+
error: `slot "${slot}" of namespace "${parent.doc.name}" does not accept ${kind} docs; it accepts ${declaredSlot.accepts.kinds.join(', ')}.`,
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
return {key: target.key, slot};
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Every adoption rule in the doc's own package that matches its group and
|
|
703
|
+
* kind, from namespaces that have a route.
|
|
704
|
+
* @param {TreeDocInput} doc
|
|
705
|
+
* @param {Map<string, TreeNamespaceInput>} declared
|
|
706
|
+
* @param {Map<string, string | null>} routeOf
|
|
707
|
+
*/
|
|
708
|
+
function adoptionsFor(doc, declared, routeOf) {
|
|
709
|
+
/** @type {Array<{key: string, namespace: TreeNamespaceInput, rule: NonNullable<NamespaceDoc['adopts']>[number]}>} */
|
|
710
|
+
const matches = [];
|
|
711
|
+
for (const [key, namespace] of declared) {
|
|
712
|
+
if (namespace.provider !== doc.provider || routeOf.get(key) == null)
|
|
713
|
+
continue;
|
|
714
|
+
for (const rule of namespace.doc.adopts ?? []) {
|
|
715
|
+
if (rule.source.group !== doc.group) continue;
|
|
716
|
+
if (
|
|
717
|
+
rule.source.kinds &&
|
|
718
|
+
!rule.source.kinds.includes(/** @type {any} */ (doc.kind))
|
|
719
|
+
) {
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
matches.push({key, namespace, rule});
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
return matches;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* The files under {@link TREE_DOCS_DIR}, sorted.
|
|
730
|
+
* @param {string} [dir]
|
|
731
|
+
* @returns {string[]}
|
|
732
|
+
*/
|
|
733
|
+
export function treeDocFiles(dir = TREE_DOCS_DIR) {
|
|
734
|
+
if (!fs.existsSync(dir)) return [];
|
|
735
|
+
return fs
|
|
736
|
+
.readdirSync(dir)
|
|
737
|
+
.filter(file => /^[\w-]+\.doc\.mjs$/u.test(file))
|
|
738
|
+
.sort(byText)
|
|
739
|
+
.map(file => path.join(dir, file));
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* The CLI's own tree inputs: the namespace docs and guides under
|
|
744
|
+
* assets/docs/tree, and, unless left out, every typed self-doc with its
|
|
745
|
+
* `namespace` group. A file that fails to load or parse is a diagnostic, never
|
|
746
|
+
* a thrown error.
|
|
747
|
+
* @param {{selfDocs?: boolean, dir?: string}} [options]
|
|
748
|
+
* @returns {Promise<{namespaces: TreeNamespaceInput[], docs: TreeDocInput[], diagnostics: CompilerDiagnostic[]}>}
|
|
749
|
+
*/
|
|
750
|
+
export async function loadTreeInputs({
|
|
751
|
+
selfDocs = true,
|
|
752
|
+
dir = TREE_DOCS_DIR,
|
|
753
|
+
} = {}) {
|
|
754
|
+
/** @type {TreeNamespaceInput[]} */
|
|
755
|
+
const namespaces = [];
|
|
756
|
+
/** @type {TreeDocInput[]} */
|
|
757
|
+
const docs = [];
|
|
758
|
+
/** @type {CompilerDiagnostic[]} */
|
|
759
|
+
const diagnostics = [];
|
|
760
|
+
for (const file of treeDocFiles(dir)) {
|
|
761
|
+
const source = packageSource(file);
|
|
762
|
+
const at = {provider: CLI_PROVIDER, source};
|
|
763
|
+
let doc;
|
|
764
|
+
try {
|
|
765
|
+
doc = await readDocView(file, {
|
|
766
|
+
root: 'tree',
|
|
767
|
+
provider: CLI_PROVIDER,
|
|
768
|
+
loader: 'native',
|
|
769
|
+
strict: true,
|
|
770
|
+
});
|
|
771
|
+
} catch (error) {
|
|
772
|
+
diagnostics.push(
|
|
773
|
+
diagnostic('invalid_doc', {
|
|
774
|
+
...at,
|
|
775
|
+
message: error instanceof Error ? error.message : String(error),
|
|
776
|
+
}),
|
|
777
|
+
);
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
const stem = path.basename(file, '.doc.mjs');
|
|
781
|
+
if (doc?.name !== stem) {
|
|
782
|
+
diagnostics.push(
|
|
783
|
+
diagnostic('invalid_doc', {
|
|
784
|
+
...at,
|
|
785
|
+
field: 'name',
|
|
786
|
+
message: `${path.basename(file)} declares name "${doc?.name}"; a docs tree file is named after its doc (${doc?.name}.doc.mjs).`,
|
|
787
|
+
}),
|
|
788
|
+
);
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
if (doc.type === 'namespace') {
|
|
792
|
+
namespaces.push({
|
|
793
|
+
provider: CLI_PROVIDER,
|
|
794
|
+
providerId: CLI_PROVIDER_ID,
|
|
795
|
+
source,
|
|
796
|
+
doc,
|
|
797
|
+
});
|
|
798
|
+
} else if (doc.type === 'generic') {
|
|
799
|
+
if (doc.placement == null) {
|
|
800
|
+
diagnostics.push(
|
|
801
|
+
diagnostic('invalid_placement', {
|
|
802
|
+
...at,
|
|
803
|
+
field: 'placement',
|
|
804
|
+
message: `${path.basename(file)} has no placement. A guide in the docs tree names its parent namespace with placement.parent.`,
|
|
805
|
+
}),
|
|
806
|
+
);
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
809
|
+
docs.push({
|
|
810
|
+
provider: CLI_PROVIDER,
|
|
811
|
+
providerId: CLI_PROVIDER_ID,
|
|
812
|
+
source,
|
|
813
|
+
kind: 'generic',
|
|
814
|
+
name: doc.name,
|
|
815
|
+
title: doc.title,
|
|
816
|
+
summary: doc.description,
|
|
817
|
+
group: null,
|
|
818
|
+
placement: doc.placement,
|
|
819
|
+
ref: {topicFile: file},
|
|
820
|
+
});
|
|
821
|
+
} else {
|
|
822
|
+
diagnostics.push(
|
|
823
|
+
diagnostic('wrong_kind', {
|
|
824
|
+
...at,
|
|
825
|
+
message: `${path.basename(file)} is stamped type ${JSON.stringify(doc?.type)}; the docs tree reads namespace and generic docs.`,
|
|
826
|
+
}),
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
if (selfDocs) {
|
|
831
|
+
const {loaded} = await loadCliSelfDocs();
|
|
832
|
+
for (const {source, doc} of loaded) {
|
|
833
|
+
docs.push({
|
|
834
|
+
provider: CLI_PROVIDER,
|
|
835
|
+
providerId: CLI_PROVIDER_ID,
|
|
836
|
+
source: `${CLI_PROVIDER}/${source}`,
|
|
837
|
+
kind: doc.type,
|
|
838
|
+
name: doc.name,
|
|
839
|
+
title: doc.displayName ?? doc.name,
|
|
840
|
+
summary: doc.summary ?? doc.description ?? '',
|
|
841
|
+
group: typeof doc.namespace === 'string' ? doc.namespace : null,
|
|
842
|
+
placement: doc.placement,
|
|
843
|
+
ref: {selfDoc: doc},
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return {namespaces, docs, diagnostics};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/** @type {Map<string, Promise<DocsTree>>} */
|
|
851
|
+
const built = new Map();
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* The CLI's own docs tree, built once per process. With `selfDocs: false` it
|
|
855
|
+
* holds only the namespaces and guides, which is all a topic list needs.
|
|
856
|
+
* @param {{selfDocs?: boolean, fresh?: boolean}} [options]
|
|
857
|
+
* @returns {Promise<DocsTree>}
|
|
858
|
+
*/
|
|
859
|
+
export function loadDocsTree({selfDocs = true, fresh = false} = {}) {
|
|
860
|
+
const key = selfDocs ? 'full' : 'namespaces';
|
|
861
|
+
let tree = fresh ? undefined : built.get(key);
|
|
862
|
+
if (!tree) {
|
|
863
|
+
tree = loadTreeInputs({selfDocs}).then(inputs => {
|
|
864
|
+
const result = buildDocsTree(inputs);
|
|
865
|
+
return {
|
|
866
|
+
...result,
|
|
867
|
+
diagnostics: sortDiagnostics([
|
|
868
|
+
...inputs.diagnostics,
|
|
869
|
+
...result.diagnostics,
|
|
870
|
+
]),
|
|
871
|
+
};
|
|
872
|
+
});
|
|
873
|
+
built.set(key, tree);
|
|
874
|
+
}
|
|
875
|
+
return tree;
|
|
876
|
+
}
|