@astryxdesign/cli 0.6.3-canary.db4e378 → 0.6.3-canary.db52d98
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -15
- 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 +14 -7
- package/api/build/build.test.mjs +184 -6
- package/api/build/build.type.d.mts +57 -2
- package/api/build/build.type.mjs +30 -7
- package/api/build/help/help.d.mts +4 -0
- package/api/build/help/help.mjs +24 -11
- package/api/build/kit/kit.d.mts +4 -1
- package/api/build/kit/kit.mjs +165 -49
- package/api/build/kit/rank.d.mts +44 -0
- package/api/build/kit/rank.mjs +432 -0
- package/api/build/kit/rank.test.mjs +196 -0
- package/api/component/_adapter.d.mts +6 -12
- package/api/component/_adapter.mjs +20 -10
- package/api/component/component.doc.mjs +1 -0
- package/api/component/component.mjs +60 -12
- package/api/component/list/list.mjs +3 -2
- package/api/discover/discover.doc.mjs +1 -0
- package/api/docs/_adapter.d.mts +252 -34
- package/api/docs/_adapter.mjs +923 -132
- package/api/docs/detail/detail.mjs +11 -3
- package/api/docs/detail/section/section.mjs +24 -13
- package/api/docs/detail/section/section.test.mjs +15 -6
- package/api/docs/docs.d.mts +5 -3
- package/api/docs/docs.doc.mjs +39 -17
- package/api/docs/docs.mjs +44 -8
- package/api/docs/docs.test.mjs +158 -4
- package/api/docs/docs.type.d.mts +181 -2
- package/api/docs/docs.type.mjs +117 -3
- package/api/docs/index/index.mjs +11 -3
- package/api/docs/index/index.test.mjs +1 -1
- package/api/docs/integration-tree.test.mjs +555 -0
- package/api/docs/integrationDocs.test.mjs +14 -14
- package/api/docs/list/list.mjs +28 -12
- package/api/docs/node/node.d.mts +43 -0
- package/api/docs/node/node.mjs +192 -0
- package/api/docs/reference-blocks.test.mjs +406 -0
- package/api/doctor/doctor.d.mts +54 -4
- package/api/doctor/doctor.doc.mjs +1 -0
- package/api/doctor/doctor.mjs +331 -16
- package/api/doctor/doctor.test.mjs +420 -7
- package/api/gap-report/gap-report.doc.mjs +1 -0
- package/api/hook/_adapter.mjs +19 -5
- package/api/hook/hook.doc.mjs +1 -0
- package/api/hook/list/list.d.mts +1 -1
- package/api/hook/list/list.mjs +69 -17
- package/api/index.d.mts +1 -1
- package/api/index.mjs +1 -0
- package/api/init/init.doc.mjs +2 -1
- package/api/integration/add-contribution.d.mts +2 -1
- package/api/integration/add-contribution.mjs +114 -12
- package/api/integration/add-contribution.test.mjs +174 -3
- package/api/integration/add-theme.mjs +34 -64
- package/api/integration/add-theme.test.mjs +105 -21
- package/api/integration/authoring-checks.mjs +138 -28
- package/api/integration/authoring-checks.test.mjs +179 -7
- package/api/integration/authoring-checks.type.mjs +6 -1
- package/api/integration/integration-authoring.type.d.mts +2 -0
- package/api/integration/integration-authoring.type.mjs +2 -0
- package/api/integration/integration-block-exports.test.mjs +10 -6
- package/api/integration/integrationAdd.doc.mjs +7 -0
- package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
- package/api/integration/integrationAddCodemod.doc.mjs +1 -0
- package/api/integration/integrationAddComponent.doc.mjs +1 -0
- package/api/integration/integrationAddDoc.doc.mjs +8 -1
- package/api/integration/integrationAddTemplate.doc.mjs +1 -0
- package/api/integration/integrationAddTheme.doc.mjs +6 -5
- package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
- package/api/integration/integrationDocConflicts.doc.mjs +2 -1
- package/api/integration/integrationPackCheck.doc.mjs +2 -1
- package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
- package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
- package/api/integration/pack-check.mjs +34 -0
- package/api/integration/pack-check.test.mjs +138 -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 +50 -102
- package/api/integration/validate-integration.test.mjs +88 -26
- package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
- package/api/integration/validateIntegration.doc.mjs +2 -1
- package/api/json/assertResponse.doc.mjs +1 -0
- package/api/json/index.ts +2 -0
- package/api/json/isError.doc.mjs +1 -0
- package/api/json/parseResponse.doc.mjs +1 -0
- package/api/layout/_adapter.mjs +20 -5
- package/api/layout/layoutCheck.doc.mjs +1 -0
- package/api/layout/layoutExpand.doc.mjs +1 -0
- package/api/layout/layoutGrammar.doc.mjs +1 -0
- package/api/search/search.d.mts +59 -1
- package/api/search/search.doc.mjs +5 -3
- package/api/search/search.mjs +458 -77
- package/api/search/search.test.mjs +91 -2
- package/api/search/search.type.d.mts +13 -1
- package/api/search/search.type.mjs +4 -1
- package/api/swizzle/swizzle.doc.mjs +1 -0
- package/api/template/list/list.mjs +1 -0
- package/api/template/table-floating-bulk-actions.test.mjs +66 -0
- package/api/template/template-integration.test.mjs +1072 -3
- package/api/template/template-suffix.test.mjs +41 -21
- package/api/template/template.doc.mjs +28 -7
- package/api/template/template.mjs +45 -8
- package/api/template/template.type.d.mts +6 -8
- package/api/template/template.type.mjs +3 -2
- package/api/theme/_adapter.d.mts +2 -3
- package/api/theme/_adapter.mjs +4 -5
- package/api/theme/add/add.binary.test.mjs +10 -17
- package/api/theme/add/add.test.mjs +14 -1
- 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/template/template.test.mjs +5 -0
- package/api/theme/themeAdd.doc.mjs +4 -3
- package/api/theme/themeBuild.doc.mjs +1 -0
- 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 +2 -1
- package/api/upgrade/_adapter.d.mts +32 -5
- package/api/upgrade/_adapter.mjs +97 -69
- package/api/upgrade/provider-agreement.test.mjs +152 -0
- package/api/upgrade/run/run.mjs +356 -59
- package/api/upgrade/upgrade.doc.mjs +6 -1
- package/api/upgrade/upgrade.type.d.mts +34 -0
- package/api/upgrade/upgrade.type.mjs +15 -0
- package/assets/codemods/__tests__/runner.test.mjs +330 -8
- package/assets/codemods/integration-discovery.mjs +8 -2
- package/assets/codemods/integration-discovery.test.mjs +15 -0
- package/assets/codemods/integration-runner.mjs +56 -4
- package/assets/codemods/integration-runner.protection.test.mjs +153 -0
- package/assets/codemods/run-codemod.mjs +177 -34
- package/assets/codemods/runner.mjs +350 -102
- package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
- package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
- package/assets/codemods/transforms/next/index.mjs +19 -1
- package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
- package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
- package/assets/docs/getting-started.doc.mjs +2 -2
- 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 +3 -3
- package/assets/docs/styling.doc.mjs +4 -4
- package/assets/docs/theme.doc.mjs +5 -5
- package/assets/docs/tokens.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +30 -0
- package/assets/docs/tree/cli.doc.mjs +23 -0
- package/assets/docs/tree/commands.doc.mjs +25 -0
- package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +66 -38
- 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 +3 -3
- 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/Item/ItemDocumentTabs.doc.mjs +14 -0
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -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/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/codemod/codemod.doc.mjs +1 -1
- package/authoring/codemod/type.ts +12 -0
- package/authoring/config/config.doc.mjs +1 -1
- package/authoring/debug/debug.doc.d.mts +11 -0
- package/authoring/debug/debug.doc.mjs +182 -0
- package/authoring/debug/parse.d.mts +3 -3
- package/authoring/doctypes/_schema.d.mts +119 -117
- package/authoring/doctypes/_schema.mjs +54 -3
- package/authoring/doctypes/base/graph-fields.doc.mjs +8 -6
- package/authoring/doctypes/base/type.ts +6 -5
- package/authoring/doctypes/command/command.doc.mjs +1 -1
- package/authoring/doctypes/command/type.ts +2 -2
- package/authoring/doctypes/component/type.ts +2 -2
- package/authoring/doctypes/doctypes-new.test.mjs +48 -6
- package/authoring/doctypes/enum/enum.doc.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +1 -1
- package/authoring/doctypes/function/function.doc.mjs +3 -2
- package/authoring/doctypes/function/type.ts +3 -2
- package/authoring/doctypes/hook/type.ts +2 -2
- package/authoring/doctypes/load-contract.test.mjs +28 -2
- package/authoring/doctypes/namespace/namespace.doc.mjs +6 -10
- package/authoring/doctypes/namespace/parse.test.mjs +23 -25
- package/authoring/doctypes/namespace/type.ts +5 -2
- package/authoring/doctypes/parse.d.mts +4 -2
- package/authoring/doctypes/parse.mjs +10 -5
- package/authoring/doctypes/reference/reference.doc.mjs +35 -6
- package/authoring/doctypes/reference/type.ts +30 -13
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +1 -2
- package/authoring/doctypes/template/parse.d.mts +2 -0
- package/authoring/doctypes/template/parse.mjs +4 -0
- package/authoring/doctypes/template/parse.test.mjs +18 -0
- package/authoring/doctypes/template/template.doc.mjs +9 -3
- package/authoring/doctypes/template/type.ts +8 -0
- 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 +2 -1
- package/authoring/gap-report/gap-report.doc.d.mts +12 -0
- package/authoring/gap-report/gap-report.doc.mjs +183 -0
- package/authoring/identity/identity.doc.mjs +2 -2
- package/authoring/index.d.mts +1 -0
- package/authoring/index.d.ts +7 -4
- package/authoring/index.mjs +2 -1
- package/authoring/integration/integration.doc.mjs +2 -2
- package/authoring/integration/type.ts +4 -10
- package/clients/cli/__tests__/cliManifest.test.ts +27 -29
- package/clients/cli/commands/blog.doc.mjs +1 -1
- package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
- package/clients/cli/commands/build-theme.mjs +11 -45
- package/clients/cli/commands/build.doc.mjs +12 -7
- package/clients/cli/commands/build.mjs +105 -67
- package/clients/cli/commands/build.text-fields.test.mjs +41 -0
- package/clients/cli/commands/component/index.mjs +1 -1
- package/clients/cli/commands/component-ownership.test.mjs +3 -3
- package/clients/cli/commands/component.doc.mjs +1 -1
- package/clients/cli/commands/discover.broken-integration.test.mjs +7 -8
- package/clients/cli/commands/discover.doc.mjs +1 -1
- package/clients/cli/commands/discover.mjs +1 -1
- package/clients/cli/commands/docs.doc.mjs +21 -9
- package/clients/cli/commands/docs.mjs +184 -70
- package/clients/cli/commands/docs.test.mjs +120 -16
- package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.test.mjs +90 -8
- package/clients/cli/commands/doctor.doc.mjs +1 -1
- package/clients/cli/commands/doctor.mjs +53 -16
- package/clients/cli/commands/gap-report.doc.mjs +1 -1
- package/clients/cli/commands/hook.doc.mjs +1 -1
- package/clients/cli/commands/init.doc.mjs +1 -1
- package/clients/cli/commands/integration-add.controls.test.mjs +1 -1
- package/clients/cli/commands/integration-add.doc.mjs +11 -1
- 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/layout-check.doc.mjs +1 -1
- package/clients/cli/commands/layout-expand.doc.mjs +1 -1
- package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
- package/clients/cli/commands/layout.doc.mjs +1 -1
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/search.doc.mjs +1 -1
- package/clients/cli/commands/search.mjs +11 -2
- package/clients/cli/commands/setup-nudge.test.mjs +6 -0
- package/clients/cli/commands/swizzle.doc.mjs +1 -1
- package/clients/cli/commands/template.doc.mjs +24 -7
- package/clients/cli/commands/template.mjs +4 -91
- package/clients/cli/commands/text-json-parity.test.mjs +719 -0
- package/clients/cli/commands/theme-add.doc.mjs +2 -2
- package/clients/cli/commands/theme-build.doc.mjs +1 -1
- package/clients/cli/commands/theme-list.doc.mjs +2 -2
- package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
- package/clients/cli/commands/theme-palette.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.doc.mjs +1 -1
- package/clients/cli/commands/theme.doc.mjs +1 -1
- package/clients/cli/commands/upgrade.doc.mjs +3 -2
- package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
- package/clients/cli/commands/upgrade.mjs +29 -7
- package/clients/cli/formatters/index.mjs +2 -0
- package/clients/cli/formatters/index.test.mjs +6 -0
- package/clients/cli/index.mjs +8 -0
- package/clients/cli/lib/hook-format.mjs +14 -5
- package/clients/cli/lib/manifest.mjs +9 -2
- package/foundation/agent-docs/agent-docs.d.mts +3 -2
- package/foundation/agent-docs/agent-docs.mjs +13 -9
- package/foundation/agent-docs/agent-docs.test.mjs +19 -1
- package/foundation/config/project-themes.test.mjs +11 -19
- package/foundation/config/project.d.mts +20 -11
- package/foundation/config/project.mjs +123 -80
- package/foundation/config/project.test.mjs +144 -21
- package/foundation/discovery/authoring-self-docs.d.mts +18 -0
- package/foundation/discovery/authoring-self-docs.mjs +37 -15
- package/foundation/discovery/authoring-self-docs.test.mjs +25 -9
- package/foundation/discovery/authoring-surface.d.mts +74 -0
- package/foundation/discovery/authoring-surface.mjs +525 -0
- package/foundation/discovery/authoring-surface.test.mjs +392 -0
- package/foundation/discovery/cli-self-docs.d.mts +119 -0
- package/foundation/discovery/cli-self-docs.mjs +490 -0
- package/foundation/discovery/cli-self-docs.test.mjs +375 -0
- package/foundation/discovery/component-discovery.d.mts +38 -0
- package/foundation/discovery/component-discovery.mjs +48 -0
- package/foundation/discovery/component-loader.d.mts +35 -38
- package/foundation/discovery/component-loader.mjs +53 -222
- package/foundation/discovery/docs-discovery.d.mts +112 -11
- package/foundation/discovery/docs-discovery.mjs +231 -36
- package/foundation/discovery/docs-discovery.test.mjs +111 -32
- package/foundation/discovery/docs-output-budget.d.mts +2 -2
- package/foundation/discovery/docs-output-budget.mjs +1 -1
- package/foundation/discovery/docs-section-key.d.mts +28 -10
- package/foundation/discovery/docs-section-key.mjs +134 -33
- package/foundation/discovery/docs-section-key.test.mjs +41 -19
- package/foundation/discovery/template-adapter.d.mts +99 -6
- package/foundation/discovery/template-adapter.mjs +480 -57
- 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/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 +220 -39
- package/foundation/doc-compiler/compile.mjs +311 -15
- 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 +28 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
- package/foundation/doc-compiler/import.d.mts +24 -0
- package/foundation/doc-compiler/import.mjs +59 -0
- package/foundation/doc-compiler/inputs.d.mts +102 -0
- package/foundation/doc-compiler/inputs.mjs +291 -0
- package/foundation/doc-compiler/inputs.test.mjs +299 -0
- package/foundation/doc-compiler/ir.d.mts +13 -0
- package/foundation/doc-compiler/ir.mjs +196 -12
- package/foundation/doc-compiler/lenses.d.mts +8 -5
- package/foundation/doc-compiler/lenses.mjs +50 -4
- package/foundation/doc-compiler/links.d.mts +162 -0
- package/foundation/doc-compiler/links.mjs +294 -0
- package/foundation/doc-compiler/links.test.mjs +192 -0
- package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
- package/foundation/doc-compiler/overlays.d.mts +37 -0
- package/foundation/doc-compiler/overlays.mjs +206 -0
- package/foundation/doc-compiler/parse-readable.d.mts +9 -0
- package/foundation/doc-compiler/parse-readable.mjs +29 -0
- package/foundation/doc-compiler/read.d.mts +127 -0
- package/foundation/doc-compiler/read.mjs +325 -0
- package/foundation/doc-compiler/read.test.mjs +313 -0
- package/foundation/doc-compiler/source.d.mts +33 -0
- package/foundation/doc-compiler/source.mjs +128 -0
- package/foundation/doc-compiler/tree.d.mts +288 -0
- package/foundation/doc-compiler/tree.mjs +876 -0
- package/foundation/doc-compiler/tree.test.mjs +598 -0
- package/foundation/fs/file-protection.d.mts +33 -0
- package/foundation/fs/file-protection.mjs +825 -0
- package/foundation/fs/file-protection.test.mjs +250 -0
- package/foundation/integrations/autolink.d.mts +58 -1
- package/foundation/integrations/autolink.mjs +143 -57
- package/foundation/integrations/autolink.test.mjs +1 -1
- package/foundation/integrations/cli-requirement.d.mts +45 -0
- package/foundation/integrations/cli-requirement.mjs +154 -0
- package/foundation/integrations/cli-requirement.test.mjs +84 -0
- package/foundation/integrations/contribution-fixes.d.mts +145 -0
- package/foundation/integrations/contribution-fixes.mjs +1284 -0
- package/foundation/integrations/contribution-inventory.d.mts +3 -2
- package/foundation/integrations/contribution-inventory.mjs +27 -24
- package/foundation/integrations/contribution-inventory.test.mjs +86 -27
- package/foundation/integrations/integration-warnings.d.mts +9 -2
- package/foundation/integrations/integration-warnings.mjs +51 -26
- package/foundation/integrations/integration-warnings.test.mjs +74 -1
- package/foundation/integrations/integrations.d.mts +3 -0
- package/foundation/integrations/integrations.mjs +11 -97
- package/foundation/integrations/provider-ledger.test.mjs +275 -0
- package/foundation/integrations/provider-resolution.d.mts +152 -0
- package/foundation/integrations/provider-resolution.mjs +576 -0
- package/foundation/integrations/provider-resolution.test.mjs +369 -0
- package/foundation/integrations/theme-descriptor.d.mts +8 -0
- package/foundation/integrations/theme-descriptor.mjs +44 -0
- package/foundation/integrations/validate-contributions.mjs +121 -29
- package/foundation/response/error-codes.d.mts +3 -1
- package/foundation/response/error-codes.d.ts +2 -0
- package/foundation/response/error-codes.doc.mjs +12 -2
- package/foundation/response/error-codes.mjs +7 -1
- package/foundation/response/error-codes.test.mjs +55 -11
- package/foundation/response/response-types.doc.d.mts +5 -1
- package/foundation/response/response-types.doc.mjs +20 -11
- package/foundation/response/response.doc.mjs +1 -1
- package/foundation/text/string-utils.d.mts +8 -0
- package/foundation/text/string-utils.mjs +40 -10
- package/foundation/xle/expand.mjs +1 -1
- package/foundation/xle/xle.test.mjs +13 -0
- package/package.json +10 -9
- package/assets/templates/themes/manifest.json +0 -95
package/api/hook/list/list.mjs
CHANGED
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
* @position api/hook/list/list.mjs — dispatched from ../hook.mjs
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
discoverHooks,
|
|
18
|
+
findHookDoc,
|
|
19
|
+
} from '../../../foundation/discovery/hook-discovery.mjs';
|
|
17
20
|
import {loadDocs} from '../../../foundation/discovery/component-loader.mjs';
|
|
18
21
|
import {AstryxError} from '../../error.mjs';
|
|
19
22
|
import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
|
|
@@ -28,7 +31,13 @@ import {resolveCoreDir} from '../_adapter.mjs';
|
|
|
28
31
|
* @param {string|null} [options.lang]
|
|
29
32
|
* @returns {Promise<import('../hook.type.mjs').HookListResponse>}
|
|
30
33
|
*/
|
|
31
|
-
export async function list({
|
|
34
|
+
export async function list({
|
|
35
|
+
cwd = process.cwd(),
|
|
36
|
+
category,
|
|
37
|
+
detail = 'names',
|
|
38
|
+
zh = false,
|
|
39
|
+
lang = null,
|
|
40
|
+
} = {}) {
|
|
32
41
|
const coreDir = resolveCoreDir(cwd);
|
|
33
42
|
const hooks = discoverHooks(coreDir);
|
|
34
43
|
|
|
@@ -51,20 +60,31 @@ export async function list({cwd = process.cwd(), category, detail = 'names', zh
|
|
|
51
60
|
const docPath = findHookDoc(coreDir, hookName);
|
|
52
61
|
if (docPath) {
|
|
53
62
|
try {
|
|
54
|
-
const docs = await loadDocs(docPath,
|
|
63
|
+
const docs = await loadDocs(docPath, {zh, lang, root: 'hooks'});
|
|
55
64
|
entries.push({
|
|
56
65
|
name: hookName,
|
|
57
66
|
description: docs.usage?.description || '',
|
|
58
67
|
import: docs.importPath || '@astryxdesign/core/hooks',
|
|
59
68
|
});
|
|
60
69
|
} catch {
|
|
61
|
-
entries.push({
|
|
70
|
+
entries.push({
|
|
71
|
+
name: hookName,
|
|
72
|
+
description: '',
|
|
73
|
+
import: '@astryxdesign/core/hooks',
|
|
74
|
+
});
|
|
62
75
|
}
|
|
63
76
|
} else {
|
|
64
|
-
entries.push({
|
|
77
|
+
entries.push({
|
|
78
|
+
name: hookName,
|
|
79
|
+
description: '',
|
|
80
|
+
import: '@astryxdesign/core/hooks',
|
|
81
|
+
});
|
|
65
82
|
}
|
|
66
83
|
}
|
|
67
|
-
return {
|
|
84
|
+
return {
|
|
85
|
+
type: 'hook.list',
|
|
86
|
+
data: {detail: 'compact', components: {[match[0]]: entries}},
|
|
87
|
+
};
|
|
68
88
|
}
|
|
69
89
|
|
|
70
90
|
if (detail === 'full') {
|
|
@@ -74,19 +94,33 @@ export async function list({cwd = process.cwd(), category, detail = 'names', zh
|
|
|
74
94
|
const docPath = findHookDoc(coreDir, hookName);
|
|
75
95
|
if (docPath) {
|
|
76
96
|
try {
|
|
77
|
-
entries.push(await loadDocs(docPath,
|
|
97
|
+
entries.push(await loadDocs(docPath, {zh, lang, root: 'hooks'}));
|
|
78
98
|
} catch {
|
|
79
|
-
entries.push(
|
|
99
|
+
entries.push(
|
|
100
|
+
/** @type {import('../hook.type.mjs').HookDoc} */ ({
|
|
101
|
+
name: hookName,
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
80
104
|
}
|
|
81
105
|
} else {
|
|
82
|
-
entries.push(
|
|
106
|
+
entries.push(
|
|
107
|
+
/** @type {import('../hook.type.mjs').HookDoc} */ ({
|
|
108
|
+
name: hookName,
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
83
111
|
}
|
|
84
112
|
}
|
|
85
|
-
return {
|
|
113
|
+
return {
|
|
114
|
+
type: 'hook.list',
|
|
115
|
+
data: {detail: 'full', components: {[match[0]]: entries}},
|
|
116
|
+
};
|
|
86
117
|
}
|
|
87
118
|
|
|
88
119
|
// Default: names only
|
|
89
|
-
return {
|
|
120
|
+
return {
|
|
121
|
+
type: 'hook.list',
|
|
122
|
+
data: {detail: 'names', components: {[match[0]]: match[1]}},
|
|
123
|
+
};
|
|
90
124
|
}
|
|
91
125
|
|
|
92
126
|
// All hooks
|
|
@@ -99,17 +133,25 @@ export async function list({cwd = process.cwd(), category, detail = 'names', zh
|
|
|
99
133
|
const docPath = findHookDoc(coreDir, hookName);
|
|
100
134
|
if (docPath) {
|
|
101
135
|
try {
|
|
102
|
-
const docs = await loadDocs(docPath,
|
|
136
|
+
const docs = await loadDocs(docPath, {zh, lang, root: 'hooks'});
|
|
103
137
|
result[cat].push({
|
|
104
138
|
name: hookName,
|
|
105
139
|
description: docs.usage?.description || '',
|
|
106
140
|
import: docs.importPath || '@astryxdesign/core/hooks',
|
|
107
141
|
});
|
|
108
142
|
} catch {
|
|
109
|
-
result[cat].push({
|
|
143
|
+
result[cat].push({
|
|
144
|
+
name: hookName,
|
|
145
|
+
description: '',
|
|
146
|
+
import: '@astryxdesign/core/hooks',
|
|
147
|
+
});
|
|
110
148
|
}
|
|
111
149
|
} else {
|
|
112
|
-
result[cat].push({
|
|
150
|
+
result[cat].push({
|
|
151
|
+
name: hookName,
|
|
152
|
+
description: '',
|
|
153
|
+
import: '@astryxdesign/core/hooks',
|
|
154
|
+
});
|
|
113
155
|
}
|
|
114
156
|
}
|
|
115
157
|
}
|
|
@@ -125,12 +167,22 @@ export async function list({cwd = process.cwd(), category, detail = 'names', zh
|
|
|
125
167
|
const docPath = findHookDoc(coreDir, hookName);
|
|
126
168
|
if (docPath) {
|
|
127
169
|
try {
|
|
128
|
-
result[cat].push(
|
|
170
|
+
result[cat].push(
|
|
171
|
+
await loadDocs(docPath, {zh, lang, root: 'hooks'}),
|
|
172
|
+
);
|
|
129
173
|
} catch {
|
|
130
|
-
result[cat].push(
|
|
174
|
+
result[cat].push(
|
|
175
|
+
/** @type {import('../hook.type.mjs').HookDoc} */ ({
|
|
176
|
+
name: hookName,
|
|
177
|
+
}),
|
|
178
|
+
);
|
|
131
179
|
}
|
|
132
180
|
} else {
|
|
133
|
-
result[cat].push(
|
|
181
|
+
result[cat].push(
|
|
182
|
+
/** @type {import('../hook.type.mjs').HookDoc} */ ({
|
|
183
|
+
name: hookName,
|
|
184
|
+
}),
|
|
185
|
+
);
|
|
134
186
|
}
|
|
135
187
|
}
|
|
136
188
|
}
|
package/api/index.d.mts
CHANGED
|
@@ -38,7 +38,7 @@ export * from "./integration/pack-check.type.mjs";
|
|
|
38
38
|
export * from "./integration/validate-integration.type.mjs";
|
|
39
39
|
export * from "./integration/authoring-checks.type.mjs";
|
|
40
40
|
export type Logger = import("./logger.mjs").Logger;
|
|
41
|
-
export { themeBuild, themeAdd, themeList, themeListAvailable, themeTargets, themePaletteGenerate, generateTonalPalette, listThemes } from "./theme/theme.mjs";
|
|
41
|
+
export { themeBuild, themeAdd, themeTemplate, themeList, themeListAvailable, themeTargets, themePaletteGenerate, generateTonalPalette, listThemes } from "./theme/theme.mjs";
|
|
42
42
|
export { layoutExpand, layoutCheck, layoutGrammar } from "./layout/layout.mjs";
|
|
43
43
|
export { integrationAdd, integrationAddAgentDoc, integrationAddCodemod, integrationAddComponent, integrationAddDoc, integrationAddTemplate } from "./integration/add-contribution.mjs";
|
|
44
44
|
export { validateIntegration, summarizeIssues } from "./integration/validate-integration.mjs";
|
package/api/index.mjs
CHANGED
package/api/init/init.doc.mjs
CHANGED
|
@@ -11,6 +11,7 @@ export const doc = {
|
|
|
11
11
|
type: 'function',
|
|
12
12
|
kind: 'api',
|
|
13
13
|
name: 'init',
|
|
14
|
+
namespace: 'cli/api',
|
|
14
15
|
displayName: 'init()',
|
|
15
16
|
summary:
|
|
16
17
|
'Non-interactive project setup: install agent docs and point at the theme + build workflows.',
|
|
@@ -101,5 +102,5 @@ export const doc = {
|
|
|
101
102
|
{label: 'Remove agent docs', code: 'await init({removeAgents: true});'},
|
|
102
103
|
],
|
|
103
104
|
command: 'init',
|
|
104
|
-
related: ['doctor', 'upgrade', 'build', '
|
|
105
|
+
related: ['doctor', 'upgrade', 'build', 'themeTemplate'],
|
|
105
106
|
};
|
|
@@ -31,7 +31,7 @@ export function integrationAddAgentDoc(line: string, options?: import("./integra
|
|
|
31
31
|
*
|
|
32
32
|
* @param {'component'|'doc'|'template'|'codemod'|'agent-doc'|'theme'} kind
|
|
33
33
|
* @param {string} name
|
|
34
|
-
* @param {{cwd?: string, dryRun?: boolean, templateType?: 'page'|'block', to?: string, replaces?: string, extends?: string}} [options]
|
|
34
|
+
* @param {{cwd?: string, dryRun?: boolean, templateType?: 'page'|'block', to?: string, replaces?: string, extends?: string, parent?: string}} [options]
|
|
35
35
|
* @returns {Promise<import('./integration-authoring.type.mjs').IntegrationAddResponse>}
|
|
36
36
|
*/
|
|
37
37
|
export function integrationAdd(kind: "component" | "doc" | "template" | "codemod" | "agent-doc" | "theme", name: string, options?: {
|
|
@@ -41,4 +41,5 @@ export function integrationAdd(kind: "component" | "doc" | "template" | "codemod
|
|
|
41
41
|
to?: string;
|
|
42
42
|
replaces?: string;
|
|
43
43
|
extends?: string;
|
|
44
|
+
parent?: string;
|
|
44
45
|
}): Promise<import("./integration-authoring.type.mjs").IntegrationAddResponse>;
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* contribution into an integration package.
|
|
6
6
|
*
|
|
7
7
|
* Dispatches component, doc, template, codemod, and agent-doc. Theme
|
|
8
|
-
* delegates to the
|
|
9
|
-
* Every root-based kind shares: first add creates the manifest; one shared
|
|
8
|
+
* delegates to the dedicated same-stem descriptor writer. Every root-based kind shares: first add creates the manifest; one shared
|
|
10
9
|
* writer; never creates `files`/`exports`; atomic staged writes; no clobber;
|
|
11
10
|
* dry-run receipt predicts real run; post-write verify through the real
|
|
12
11
|
* discovery/parser seam.
|
|
@@ -35,6 +34,11 @@ import {
|
|
|
35
34
|
} from '../../foundation/integrations/integrations.mjs';
|
|
36
35
|
import {isValidSemver} from '../../foundation/env/semver.mjs';
|
|
37
36
|
import {assertContributionVisible} from '../../foundation/integrations/contribution-inventory.mjs';
|
|
37
|
+
import {
|
|
38
|
+
docsTreeCliProblem,
|
|
39
|
+
withDocsTreeCli,
|
|
40
|
+
} from '../../foundation/integrations/cli-requirement.mjs';
|
|
41
|
+
import {discoverIntegrationDocs} from '../../foundation/discovery/docs-discovery.mjs';
|
|
38
42
|
import {findIntegrationComponentDoc} from '../../foundation/discovery/component-discovery.mjs';
|
|
39
43
|
import {parseAgentDocsField} from '../../authoring/integration/schema.mjs';
|
|
40
44
|
import {integrationAddTheme} from './add-theme.mjs';
|
|
@@ -84,6 +88,17 @@ function resolvePackage(cwd) {
|
|
|
84
88
|
}
|
|
85
89
|
const owner = typeof pkg.name === 'string' ? pkg.name : '(local integration)';
|
|
86
90
|
const existingManifest = findLocalIntegrationManifestOrNull(packageDir);
|
|
91
|
+
// The nearest package.json above the cwd may belong to another package (an
|
|
92
|
+
// app that contains the folder). Only a package that is already an
|
|
93
|
+
// integration is found from a subfolder; the first add runs in the package.
|
|
94
|
+
const here = path.resolve(cwd ?? process.cwd());
|
|
95
|
+
if (existingManifest == null && path.resolve(packageDir) !== here) {
|
|
96
|
+
throw new AstryxError(
|
|
97
|
+
`${here} has no package.json. The nearest is ${packageFile} (${owner}), which is not an Astryx integration yet. Run this in your integration package's own directory, next to its package.json.`,
|
|
98
|
+
undefined,
|
|
99
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
87
102
|
const manifestFile =
|
|
88
103
|
existingManifest ?? path.join(packageDir, 'astryx.integration.mjs');
|
|
89
104
|
return {
|
|
@@ -263,7 +278,7 @@ async function addComponent(name, options) {
|
|
|
263
278
|
const sourcePath = projectPath(path.relative(packageDir, sourceFile));
|
|
264
279
|
const extensionlessPath = sourcePath.replace(/\.tsx?$/u, '');
|
|
265
280
|
const importSpecifier = `${owner}/${extensionlessPath}`;
|
|
266
|
-
const docContents =
|
|
281
|
+
const docContents = `/** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */\nexport default {\n type: 'component',\n name: '${name}',\n displayName: '${name}',\n import: ${JSON.stringify(importSpecifier)},\n usage: {description: '${name} component.'},\n props: [],\n};\n`;
|
|
267
282
|
const sourceContents = `export function ${name}() {\n return <div>${name}</div>;\n}\n`;
|
|
268
283
|
|
|
269
284
|
/** @type {import('./add-helpers.mjs').WritePlan[]} */
|
|
@@ -354,7 +369,7 @@ async function addComponent(name, options) {
|
|
|
354
369
|
|
|
355
370
|
/**
|
|
356
371
|
* @param {string} name topic name (must match [\w-]+)
|
|
357
|
-
* @param {{cwd?: string, dryRun?: boolean, replaces?: string, extends?: string}} options
|
|
372
|
+
* @param {{cwd?: string, dryRun?: boolean, replaces?: string, extends?: string, parent?: string}} options
|
|
358
373
|
* @returns {Promise<import('./integration-authoring.type.mjs').IntegrationAddResponse>}
|
|
359
374
|
*/
|
|
360
375
|
async function addDoc(name, options) {
|
|
@@ -373,6 +388,20 @@ async function addDoc(name, options) {
|
|
|
373
388
|
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
374
389
|
);
|
|
375
390
|
}
|
|
391
|
+
if (options.parent != null && (options.replaces != null || options.extends != null)) {
|
|
392
|
+
throw new AstryxError(
|
|
393
|
+
'A guide placed in a namespace has its own route: it cannot also replace or extend a topic.',
|
|
394
|
+
undefined,
|
|
395
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
if (options.parent != null && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(options.parent)) {
|
|
399
|
+
throw new AstryxError(
|
|
400
|
+
'--parent must name a namespace in lowercase letters and digits joined by single hyphens, such as "acme".',
|
|
401
|
+
undefined,
|
|
402
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
403
|
+
);
|
|
404
|
+
}
|
|
376
405
|
for (const [option, value] of [
|
|
377
406
|
['--replaces', options.replaces],
|
|
378
407
|
['--extends', options.extends],
|
|
@@ -433,20 +462,92 @@ async function addDoc(name, options) {
|
|
|
433
462
|
}
|
|
434
463
|
|
|
435
464
|
const title = kebabToTitle(name);
|
|
465
|
+
// --parent names a namespace of this package by its name, wherever its file
|
|
466
|
+
// is. An existing one is used as it is: its `guides` slot, or else its only
|
|
467
|
+
// slot that takes a guide. Otherwise the namespace doc is written, unless a
|
|
468
|
+
// file of that name is already something else (spec:AST-046 FR11).
|
|
469
|
+
const namespaceFile =
|
|
470
|
+
options.parent == null
|
|
471
|
+
? null
|
|
472
|
+
: assertWithin(`${options.parent}.doc.mjs`, root, {
|
|
473
|
+
label: 'namespace doc file',
|
|
474
|
+
});
|
|
475
|
+
let parentSlot = 'guides';
|
|
476
|
+
let writeNamespace = false;
|
|
477
|
+
if (options.parent != null && namespaceFile != null) {
|
|
478
|
+
const {namespaces} = await discoverIntegrationDocs({
|
|
479
|
+
name: owner,
|
|
480
|
+
docs: root,
|
|
481
|
+
});
|
|
482
|
+
const existing = namespaces.find(ns => ns.doc.name === options.parent);
|
|
483
|
+
if (existing != null) {
|
|
484
|
+
const takesGuides = Object.entries(existing.doc.slots ?? {})
|
|
485
|
+
.filter(([, slot]) => slot?.accepts?.kinds?.includes('generic'))
|
|
486
|
+
.map(([slotName]) => slotName);
|
|
487
|
+
const slot = takesGuides.includes('guides')
|
|
488
|
+
? 'guides'
|
|
489
|
+
: takesGuides.length === 1
|
|
490
|
+
? takesGuides[0]
|
|
491
|
+
: null;
|
|
492
|
+
if (slot == null) {
|
|
493
|
+
throw new AstryxError(
|
|
494
|
+
takesGuides.length === 0
|
|
495
|
+
? `Namespace "${options.parent}" (${existing.source}) has no slot that takes a guide. Add one, such as guides: {title: 'Guides', accepts: {kinds: ['generic']}}.`
|
|
496
|
+
: `Namespace "${options.parent}" (${existing.source}) has more than one slot that takes a guide (${takesGuides.join(', ')}). Write the guide yourself, and name its slot in its placement.`,
|
|
497
|
+
undefined,
|
|
498
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
parentSlot = slot;
|
|
502
|
+
} else if (fs.existsSync(namespaceFile)) {
|
|
503
|
+
throw new AstryxError(
|
|
504
|
+
`${projectPath(path.relative(packageDir, namespaceFile))} exists but does not load as the namespace "${options.parent}". Fix or rename that file, or pass another --parent.`,
|
|
505
|
+
undefined,
|
|
506
|
+
ERROR_CODES.ERR_FILE_EXISTS,
|
|
507
|
+
);
|
|
508
|
+
} else {
|
|
509
|
+
writeNamespace = true;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
436
512
|
const relationship = options.replaces
|
|
437
513
|
? `\n replaces: '${options.replaces}',`
|
|
438
514
|
: options.extends
|
|
439
515
|
? `\n extends: '${options.extends}',`
|
|
440
|
-
:
|
|
441
|
-
|
|
516
|
+
: options.parent
|
|
517
|
+
? `\n placement: {parent: 'namespace:${options.parent}', slot: '${parentSlot}'},`
|
|
518
|
+
: '';
|
|
519
|
+
const namespaceTitle =
|
|
520
|
+
options.parent == null ? '' : kebabToTitle(options.parent);
|
|
521
|
+
const namespaceContents = `/** @type {import('@astryxdesign/cli/authoring').NamespaceDoc} */\nexport default {\n type: 'namespace',\n name: '${options.parent}',\n title: '${namespaceTitle}',\n summary: 'Guides for ${namespaceTitle}.',\n slots: {\n guides: {title: 'Guides', accepts: {kinds: ['generic']}},\n },\n};\n`;
|
|
522
|
+
const docContents = `/** @type {import('@astryxdesign/cli/authoring').ReferenceDoc} */\nexport default {\n type: 'generic',\n name: '${name}',\n title: '${title}',\n description: '${title} documentation.',${relationship}\n sections: [\n {\n title: 'Overview',\n content: [\n { type: 'prose', text: '${title} documentation.' },\n ],\n },\n ],\n};\n`;
|
|
442
523
|
|
|
443
524
|
/** @type {import('./add-helpers.mjs').WritePlan[]} */
|
|
444
525
|
const plans = [{path: docFile, contents: docContents, createOnly: true}];
|
|
445
|
-
|
|
526
|
+
if (namespaceFile != null && writeNamespace) {
|
|
527
|
+
plans.push({path: namespaceFile, contents: namespaceContents, createOnly: true});
|
|
528
|
+
}
|
|
529
|
+
let pkgUpdate = packageJsonUpdate(
|
|
446
530
|
packageFile,
|
|
447
531
|
rootPath,
|
|
448
532
|
path.basename(manifestFile),
|
|
449
533
|
);
|
|
534
|
+
// A namespace doc needs a CLI that reads it: an older one hides every doc
|
|
535
|
+
// topic the package ships. Declare that CLI as a peer, so an older one fails
|
|
536
|
+
// at install instead (spec:AST-046 FR11).
|
|
537
|
+
if (options.parent != null) {
|
|
538
|
+
const expectedOriginal =
|
|
539
|
+
pkgUpdate?.expectedOriginal ?? fs.readFileSync(packageFile);
|
|
540
|
+
const text = pkgUpdate?.contents ?? expectedOriginal.toString('utf-8');
|
|
541
|
+
const current = JSON.parse(text);
|
|
542
|
+
if (docsTreeCliProblem(current) != null) {
|
|
543
|
+
pkgUpdate = {
|
|
544
|
+
contents:
|
|
545
|
+
JSON.stringify(withDocsTreeCli(current), null, 2) +
|
|
546
|
+
(text.endsWith('\n') ? '\n' : ''),
|
|
547
|
+
expectedOriginal,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
}
|
|
450
551
|
if (pkgUpdate != null) {
|
|
451
552
|
plans.push({
|
|
452
553
|
path: packageFile,
|
|
@@ -565,8 +666,8 @@ async function addTemplate(name, options) {
|
|
|
565
666
|
throw error;
|
|
566
667
|
}
|
|
567
668
|
|
|
568
|
-
const specFile = assertWithin(`${name}.
|
|
569
|
-
label: 'template
|
|
669
|
+
const specFile = assertWithin(`${name}.doc.mjs`, root, {
|
|
670
|
+
label: 'template descriptor',
|
|
570
671
|
});
|
|
571
672
|
const sourceFile = assertWithin(`${name}.tsx`, root, {
|
|
572
673
|
label: 'template source',
|
|
@@ -589,7 +690,8 @@ async function addTemplate(name, options) {
|
|
|
589
690
|
const pascalName = kebabToPascal(name);
|
|
590
691
|
const sourcePath = projectPath(path.relative(packageDir, sourceFile));
|
|
591
692
|
const extensionlessPath = sourcePath.replace(/\.tsx?$/u, '');
|
|
592
|
-
const
|
|
693
|
+
const blockFields = templateType === 'block' ? '\n aspectRatio: 1,' : '';
|
|
694
|
+
const specContents = `/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */\nexport default {\n type: '${templateType}',\n name: '${name}',\n displayName: '${kebabToTitle(name)}',\n description: '${kebabToTitle(name)} template.',${blockFields}\n};\n`;
|
|
593
695
|
const sourceContents = `export default function ${pascalName}() {\n return <div>${kebabToTitle(name)}</div>;\n}\n`;
|
|
594
696
|
|
|
595
697
|
/** @type {import('./add-helpers.mjs').WritePlan[]} */
|
|
@@ -1105,7 +1207,7 @@ export function integrationAddAgentDoc(line, options = {}) {
|
|
|
1105
1207
|
|
|
1106
1208
|
const KIND_OPTIONS = {
|
|
1107
1209
|
component: new Set(['cwd', 'dryRun']),
|
|
1108
|
-
doc: new Set(['cwd', 'dryRun', 'replaces', 'extends']),
|
|
1210
|
+
doc: new Set(['cwd', 'dryRun', 'replaces', 'extends', 'parent']),
|
|
1109
1211
|
template: new Set(['cwd', 'dryRun', 'templateType']),
|
|
1110
1212
|
codemod: new Set(['cwd', 'dryRun', 'to']),
|
|
1111
1213
|
'agent-doc': new Set(['cwd', 'dryRun']),
|
|
@@ -1136,7 +1238,7 @@ function validateKindOptions(kind, options) {
|
|
|
1136
1238
|
*
|
|
1137
1239
|
* @param {'component'|'doc'|'template'|'codemod'|'agent-doc'|'theme'} kind
|
|
1138
1240
|
* @param {string} name
|
|
1139
|
-
* @param {{cwd?: string, dryRun?: boolean, templateType?: 'page'|'block', to?: string, replaces?: string, extends?: string}} [options]
|
|
1241
|
+
* @param {{cwd?: string, dryRun?: boolean, templateType?: 'page'|'block', to?: string, replaces?: string, extends?: string, parent?: string}} [options]
|
|
1140
1242
|
* @returns {Promise<import('./integration-authoring.type.mjs').IntegrationAddResponse>}
|
|
1141
1243
|
*/
|
|
1142
1244
|
export async function integrationAdd(kind, name, options = {}) {
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
integrationAddTemplate,
|
|
13
13
|
} from './add-contribution.mjs';
|
|
14
14
|
import {validateLocalIntegration} from './validate-integration.mjs';
|
|
15
|
+
import {DOCS_TREE_CLI} from '../../foundation/integrations/cli-requirement.mjs';
|
|
15
16
|
|
|
16
17
|
let tmpDir;
|
|
17
18
|
|
|
@@ -77,6 +78,7 @@ describe('integrationAdd component', () => {
|
|
|
77
78
|
path.join(tmpDir, 'components/MyWidget.doc.mjs'),
|
|
78
79
|
'utf-8',
|
|
79
80
|
);
|
|
81
|
+
expect(doc).toContain("@astryxdesign/cli/authoring').ComponentDoc");
|
|
80
82
|
expect(doc).toContain("type: 'component'");
|
|
81
83
|
expect(doc).toContain("name: 'MyWidget'");
|
|
82
84
|
expect(doc).toContain('props: []');
|
|
@@ -304,6 +306,7 @@ describe('integrationAdd doc', () => {
|
|
|
304
306
|
path.join(tmpDir, 'docs/my-guide.doc.mjs'),
|
|
305
307
|
'utf-8',
|
|
306
308
|
);
|
|
309
|
+
expect(doc).toContain("@astryxdesign/cli/authoring').ReferenceDoc");
|
|
307
310
|
expect(doc).toContain("type: 'generic'");
|
|
308
311
|
expect(doc).toContain("name: 'my-guide'");
|
|
309
312
|
|
|
@@ -312,6 +315,142 @@ describe('integrationAdd doc', () => {
|
|
|
312
315
|
expect(docErrors).toEqual([]);
|
|
313
316
|
});
|
|
314
317
|
|
|
318
|
+
it('refuses to write from a folder with no package.json into the package above it', async () => {
|
|
319
|
+
setupBare();
|
|
320
|
+
const inside = path.join(tmpDir, 'kit');
|
|
321
|
+
fs.mkdirSync(inside);
|
|
322
|
+
await expect(
|
|
323
|
+
integrationAdd('doc', 'my-guide', {cwd: inside, parent: 'acme'}),
|
|
324
|
+
).rejects.toMatchObject({
|
|
325
|
+
code: 'ERR_INVALID_ARGUMENT',
|
|
326
|
+
message: expect.stringContaining('has no package.json'),
|
|
327
|
+
});
|
|
328
|
+
expect(fs.existsSync(path.join(tmpDir, 'docs'))).toBe(false);
|
|
329
|
+
expect(fs.existsSync(path.join(tmpDir, 'astryx.integration.mjs'))).toBe(false);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('finds an integration from a folder inside it', async () => {
|
|
333
|
+
setup();
|
|
334
|
+
const inside = path.join(tmpDir, 'src');
|
|
335
|
+
fs.mkdirSync(inside);
|
|
336
|
+
const result = await integrationAdd('doc', 'my-guide', {cwd: inside});
|
|
337
|
+
expect(result.data.files).toContain('docs/my-guide.doc.mjs');
|
|
338
|
+
expect(fs.existsSync(path.join(tmpDir, 'docs/my-guide.doc.mjs'))).toBe(true);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('places a guide in a namespace of the package, writing the namespace once', async () => {
|
|
342
|
+
setup();
|
|
343
|
+
const first = await integrationAdd('doc', 'deploying', {
|
|
344
|
+
cwd: tmpDir,
|
|
345
|
+
parent: 'acme',
|
|
346
|
+
});
|
|
347
|
+
expect(first.data.files).toEqual(
|
|
348
|
+
expect.arrayContaining(['docs/deploying.doc.mjs', 'docs/acme.doc.mjs']),
|
|
349
|
+
);
|
|
350
|
+
const guide = fs.readFileSync(path.join(tmpDir, 'docs/deploying.doc.mjs'), 'utf-8');
|
|
351
|
+
expect(guide).toContain("placement: {parent: 'namespace:acme', slot: 'guides'}");
|
|
352
|
+
const namespace = fs.readFileSync(path.join(tmpDir, 'docs/acme.doc.mjs'), 'utf-8');
|
|
353
|
+
expect(namespace).toContain("type: 'namespace'");
|
|
354
|
+
expect(namespace).toContain("guides: {title: 'Guides', accepts: {kinds: ['generic']}}");
|
|
355
|
+
|
|
356
|
+
// The namespace doc needs a CLI that reads it, declared as an optional peer.
|
|
357
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'));
|
|
358
|
+
expect(pkg.peerDependencies).toEqual({'@astryxdesign/cli': `>=${DOCS_TREE_CLI}`});
|
|
359
|
+
expect(pkg.peerDependenciesMeta).toEqual({'@astryxdesign/cli': {optional: true}});
|
|
360
|
+
|
|
361
|
+
const second = await integrationAdd('doc', 'upgrading', {
|
|
362
|
+
cwd: tmpDir,
|
|
363
|
+
parent: 'acme',
|
|
364
|
+
});
|
|
365
|
+
expect(second.data.files).not.toContain('docs/acme.doc.mjs');
|
|
366
|
+
|
|
367
|
+
const validation = await validateLocalIntegration(tmpDir);
|
|
368
|
+
expect(validation.issues.filter(i => i.code === 'invalid_doc')).toEqual([]);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('finds the --parent namespace by its name, wherever its file is, and uses its slot', async () => {
|
|
372
|
+
setup({manifest: "export default {docs: './docs'};\n"});
|
|
373
|
+
fs.mkdirSync(path.join(tmpDir, 'docs', 'ns'), {recursive: true});
|
|
374
|
+
fs.writeFileSync(
|
|
375
|
+
path.join(tmpDir, 'docs', 'ns', 'acme.doc.mjs'),
|
|
376
|
+
"export default {type: 'namespace', name: 'acme', title: 'Acme', summary: 'Acme.', slots: {items: {title: 'Items', accepts: {kinds: ['generic']}}}};\n",
|
|
377
|
+
);
|
|
378
|
+
const result = await integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'acme'});
|
|
379
|
+
expect(result.data.files).not.toContain('docs/acme.doc.mjs');
|
|
380
|
+
expect(fs.existsSync(path.join(tmpDir, 'docs', 'acme.doc.mjs'))).toBe(false);
|
|
381
|
+
expect(fs.readFileSync(path.join(tmpDir, 'docs', 'deploying.doc.mjs'), 'utf-8')).toContain(
|
|
382
|
+
"placement: {parent: 'namespace:acme', slot: 'items'}",
|
|
383
|
+
);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('refuses --parent when its file is not that namespace, or the namespace has no slot for a guide', async () => {
|
|
387
|
+
setup({manifest: "export default {docs: './docs'};\n"});
|
|
388
|
+
fs.mkdirSync(path.join(tmpDir, 'docs'), {recursive: true});
|
|
389
|
+
const nsFile = path.join(tmpDir, 'docs', 'acme.doc.mjs');
|
|
390
|
+
fs.writeFileSync(
|
|
391
|
+
nsFile,
|
|
392
|
+
"export default {type: 'generic', name: 'acme', title: 'Acme', description: 'A topic.', sections: [{title: 'Only', content: [{type: 'prose', text: 'x'}]}]};\n",
|
|
393
|
+
);
|
|
394
|
+
await expect(
|
|
395
|
+
integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'acme'}),
|
|
396
|
+
).rejects.toMatchObject({code: 'ERR_FILE_EXISTS'});
|
|
397
|
+
// A fresh file: the module loader keeps the first import of a path.
|
|
398
|
+
fs.writeFileSync(
|
|
399
|
+
path.join(tmpDir, 'docs', 'beta.doc.mjs'),
|
|
400
|
+
"export default {type: 'namespace', name: 'beta', title: 'Beta', summary: 'Beta.', slots: {items: {title: 'Items', accepts: {kinds: ['function']}}}};\n",
|
|
401
|
+
);
|
|
402
|
+
await expect(
|
|
403
|
+
integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'beta'}),
|
|
404
|
+
).rejects.toMatchObject({
|
|
405
|
+
code: 'ERR_INVALID_ARGUMENT',
|
|
406
|
+
message: expect.stringContaining('no slot that takes a guide'),
|
|
407
|
+
});
|
|
408
|
+
fs.writeFileSync(
|
|
409
|
+
path.join(tmpDir, 'docs', 'gamma.doc.mjs'),
|
|
410
|
+
"export default {type: 'namespace', name: 'gamma', title: 'Gamma', summary: 'Gamma.', slots: {guides: {title: 'Guides', accepts: {kinds: ['function']}}, more: {title: 'More', accepts: {kinds: ['generic']}}, extra: {title: 'Extra', accepts: {kinds: ['generic']}}}};\n",
|
|
411
|
+
);
|
|
412
|
+
await expect(
|
|
413
|
+
integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'gamma'}),
|
|
414
|
+
).rejects.toMatchObject({
|
|
415
|
+
code: 'ERR_INVALID_ARGUMENT',
|
|
416
|
+
message: expect.stringContaining('more than one slot that takes a guide (more, extra)'),
|
|
417
|
+
});
|
|
418
|
+
expect(fs.existsSync(path.join(tmpDir, 'docs', 'deploying.doc.mjs'))).toBe(false);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('raises a CLI peer that admits a CLI too old for namespace docs, and keeps one that does not', async () => {
|
|
422
|
+
setup();
|
|
423
|
+
const file = path.join(tmpDir, 'package.json');
|
|
424
|
+
const write = (/** @type {string} */ range) => {
|
|
425
|
+
const pkg = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
426
|
+
pkg.peerDependencies = {'@astryxdesign/cli': range};
|
|
427
|
+
fs.writeFileSync(file, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
428
|
+
};
|
|
429
|
+
write('^0.6.0');
|
|
430
|
+
await integrationAdd('doc', 'deploying', {cwd: tmpDir, parent: 'acme'});
|
|
431
|
+
expect(JSON.parse(fs.readFileSync(file, 'utf-8')).peerDependencies).toEqual({
|
|
432
|
+
'@astryxdesign/cli': `>=${DOCS_TREE_CLI}`,
|
|
433
|
+
});
|
|
434
|
+
write('^9.1.0');
|
|
435
|
+
await integrationAdd('doc', 'upgrading', {cwd: tmpDir, parent: 'acme'});
|
|
436
|
+
expect(JSON.parse(fs.readFileSync(file, 'utf-8')).peerDependencies).toEqual({
|
|
437
|
+
'@astryxdesign/cli': '^9.1.0',
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
it('refuses --parent with a relationship, or a namespace name that is not a route segment', async () => {
|
|
442
|
+
setup();
|
|
443
|
+
await expect(
|
|
444
|
+
integrationAdd('doc', 'x', {cwd: tmpDir, parent: 'acme', replaces: 'getting-started'}),
|
|
445
|
+
).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
|
|
446
|
+
await expect(
|
|
447
|
+
integrationAdd('doc', 'x', {cwd: tmpDir, parent: 'Acme Kit'}),
|
|
448
|
+
).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
|
|
449
|
+
await expect(
|
|
450
|
+
integrationAdd('template', 'x', {cwd: tmpDir, parent: 'acme'}),
|
|
451
|
+
).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
|
|
452
|
+
});
|
|
453
|
+
|
|
315
454
|
it('includes replaces in the generated doc', async () => {
|
|
316
455
|
setup();
|
|
317
456
|
const result = await integrationAdd('doc', 'my-tokens', {
|
|
@@ -390,13 +529,14 @@ describe('integrationAdd template', () => {
|
|
|
390
529
|
expect(result.data.kind).toBe('template');
|
|
391
530
|
expect(result.data.name).toBe('my-widget');
|
|
392
531
|
expect(result.data.root).toEqual({path: './templates', created: true});
|
|
393
|
-
expect(result.data.files).toContain('templates/my-widget.
|
|
532
|
+
expect(result.data.files).toContain('templates/my-widget.doc.mjs');
|
|
394
533
|
expect(result.data.files).toContain('templates/my-widget.tsx');
|
|
395
534
|
|
|
396
535
|
const spec = fs.readFileSync(
|
|
397
|
-
path.join(tmpDir, 'templates/my-widget.
|
|
536
|
+
path.join(tmpDir, 'templates/my-widget.doc.mjs'),
|
|
398
537
|
'utf-8',
|
|
399
538
|
);
|
|
539
|
+
expect(spec).toContain("@astryxdesign/cli/authoring').TemplateDoc");
|
|
400
540
|
expect(spec).toContain("type: 'page'");
|
|
401
541
|
expect(spec).toContain("name: 'my-widget'");
|
|
402
542
|
|
|
@@ -432,10 +572,11 @@ describe('integrationAdd template', () => {
|
|
|
432
572
|
templateType: 'block',
|
|
433
573
|
});
|
|
434
574
|
const spec = fs.readFileSync(
|
|
435
|
-
path.join(tmpDir, 'templates/my-card.
|
|
575
|
+
path.join(tmpDir, 'templates/my-card.doc.mjs'),
|
|
436
576
|
'utf-8',
|
|
437
577
|
);
|
|
438
578
|
expect(spec).toContain("type: 'block'");
|
|
579
|
+
expect(spec).toContain('aspectRatio: 1');
|
|
439
580
|
});
|
|
440
581
|
|
|
441
582
|
it('rejects an invalid template type', async () => {
|
|
@@ -676,6 +817,35 @@ describe('custom root preservation', () => {
|
|
|
676
817
|
});
|
|
677
818
|
});
|
|
678
819
|
|
|
820
|
+
describe('typed descriptor conformance', () => {
|
|
821
|
+
it('emits a strongly typed .doc.mjs for every canonical item writer', async () => {
|
|
822
|
+
setup();
|
|
823
|
+
await integrationAdd('component', 'MyWidget', {cwd: tmpDir});
|
|
824
|
+
await integrationAdd('doc', 'my-guide', {cwd: tmpDir});
|
|
825
|
+
await integrationAdd('template', 'my-page', {cwd: tmpDir});
|
|
826
|
+
await integrationAdd('theme', 'ocean', {cwd: tmpDir});
|
|
827
|
+
|
|
828
|
+
// Codemod and agent-doc keep their released formats for compatibility;
|
|
829
|
+
// no new kind may copy those exceptions.
|
|
830
|
+
for (const [relativePath, type] of [
|
|
831
|
+
['components/MyWidget.doc.mjs', 'ComponentDoc'],
|
|
832
|
+
['docs/my-guide.doc.mjs', 'ReferenceDoc'],
|
|
833
|
+
['templates/my-page.doc.mjs', 'TemplateDoc'],
|
|
834
|
+
['themes/ocean/oceanTheme.doc.mjs', 'ThemeDoc'],
|
|
835
|
+
]) {
|
|
836
|
+
const source = fs.readFileSync(path.join(tmpDir, relativePath), 'utf-8');
|
|
837
|
+
expect(source).toContain(`@astryxdesign/cli/authoring').${type}`);
|
|
838
|
+
expect(source).toContain('export default {');
|
|
839
|
+
}
|
|
840
|
+
expect(
|
|
841
|
+
fs.existsSync(path.join(tmpDir, 'templates/my-page.template.mjs')),
|
|
842
|
+
).toBe(false);
|
|
843
|
+
expect(fs.existsSync(path.join(tmpDir, 'themes/manifest.json'))).toBe(
|
|
844
|
+
false,
|
|
845
|
+
);
|
|
846
|
+
});
|
|
847
|
+
});
|
|
848
|
+
|
|
679
849
|
describe('public per-kind APIs', () => {
|
|
680
850
|
it('exposes narrow functions for every non-theme contribution kind', async () => {
|
|
681
851
|
setup();
|
|
@@ -711,6 +881,7 @@ describe('public dispatcher', () => {
|
|
|
711
881
|
const result = await integrationAdd('theme', 'ocean', {cwd: tmpDir});
|
|
712
882
|
expect(result.data).toMatchObject({kind: 'theme', name: 'ocean'});
|
|
713
883
|
expect(result.data.files).toContain('themes/ocean/oceanTheme.ts');
|
|
884
|
+
expect(result.data.files).toContain('themes/ocean/oceanTheme.doc.mjs');
|
|
714
885
|
});
|
|
715
886
|
|
|
716
887
|
it('refuses a kind-specific option on the wrong kind', async () => {
|