@astryxdesign/cli 0.6.4-canary.f0355e3 → 0.6.4
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 +96 -99
- package/api/build/build.doc.mjs +1 -6
- package/api/build/build.test.mjs +0 -22
- package/api/build/kit/kit.mjs +5 -44
- package/api/component/_adapter.d.mts +0 -25
- package/api/component/_adapter.mjs +5 -59
- package/api/component/component.d.mts +3 -6
- package/api/component/component.doc.mjs +17 -37
- package/api/component/component.mjs +9 -249
- package/api/component/component.type.d.mts +0 -25
- package/api/component/component.type.mjs +0 -44
- package/api/discover/_adapter.d.mts +6 -114
- package/api/discover/_adapter.mjs +17 -372
- package/api/discover/detail/detail.d.mts +6 -18
- package/api/discover/detail/detail.mjs +13 -67
- package/api/discover/detail/detail.test.mjs +0 -85
- package/api/discover/discover.d.mts +9 -3
- package/api/discover/discover.doc.mjs +18 -61
- package/api/discover/discover.mjs +36 -220
- package/api/discover/discover.test.mjs +2 -11
- package/api/discover/discover.type.d.mts +8 -147
- package/api/discover/discover.type.mjs +12 -102
- package/api/discover/list/list.d.mts +6 -20
- package/api/discover/list/list.mjs +12 -45
- package/api/discover/list/list.test.mjs +0 -46
- package/api/discover/search/search.d.mts +16 -18
- package/api/discover/search/search.mjs +56 -102
- package/api/discover/search/search.test.mjs +10 -144
- package/api/docs/_adapter.d.mts +3 -8
- package/api/docs/_adapter.mjs +6 -14
- package/api/docs/docOverlays.test.mjs +1 -27
- package/api/docs/docs.doc.mjs +2 -2
- package/api/docs/docs.test.mjs +243 -0
- package/api/docs/integration-tree.test.mjs +555 -0
- package/api/docs/integrationDocs.test.mjs +314 -0
- package/api/doctor/doctor.d.mts +3 -8
- package/api/doctor/doctor.doc.mjs +8 -17
- package/api/doctor/doctor.mjs +9 -90
- package/api/doctor/doctor.test.mjs +10 -122
- package/api/doctor/doctor.type.d.mts +1 -1
- package/api/doctor/doctor.type.mjs +1 -1
- package/api/gap-report/gap-report.doc.mjs +10 -19
- package/api/hook/hook.doc.mjs +3 -6
- package/api/index.d.mts +2 -1
- package/api/index.mjs +5 -5
- package/api/init/init.doc.mjs +12 -17
- package/api/integration/add-helpers.d.mts +2 -5
- package/api/integration/add-helpers.mjs +9 -36
- package/api/integration/add-theme.mjs +1 -22
- package/api/integration/add-theme.test.mjs +0 -34
- package/api/integration/authoring-checks.mjs +2 -2
- package/api/integration/integrationPackCheck.doc.mjs +3 -3
- package/api/integration/pack-check.mjs +9 -82
- package/api/integration/pack-check.test.mjs +0 -90
- package/api/integration/pack-check.type.mjs +1 -1
- package/api/json/assertResponse.doc.mjs +1 -1
- package/api/json/index.ts +1 -0
- package/api/json/isError.doc.mjs +1 -1
- package/api/layout/_adapter.d.mts +34 -0
- package/api/layout/_adapter.mjs +148 -0
- package/api/layout/check/check.d.mts +16 -0
- package/api/layout/check/check.mjs +40 -0
- package/api/layout/expand/expand.d.mts +22 -0
- package/api/layout/expand/expand.mjs +155 -0
- package/api/layout/expand/expand.path-safety.test.mjs +53 -0
- package/api/layout/grammar/grammar.d.mts +13 -0
- package/api/layout/grammar/grammar.mjs +87 -0
- package/api/layout/layout.d.mts +6 -0
- package/api/layout/layout.mjs +17 -0
- package/api/layout/layout.test.mjs +297 -0
- package/api/layout/layout.type.d.mts +89 -0
- package/api/layout/layout.type.mjs +103 -0
- package/api/layout/layoutCheck.doc.d.mts +11 -0
- package/api/layout/layoutCheck.doc.mjs +85 -0
- package/api/layout/layoutExpand.doc.d.mts +11 -0
- package/api/layout/layoutExpand.doc.mjs +107 -0
- package/api/layout/layoutGrammar.doc.d.mts +11 -0
- package/api/layout/layoutGrammar.doc.mjs +57 -0
- package/api/search/search.d.mts +1 -27
- package/api/search/search.doc.mjs +2 -2
- package/api/search/search.mjs +16 -228
- package/api/search/search.test.mjs +512 -0
- package/api/swizzle/swizzle.doc.mjs +5 -7
- package/api/template/copy/copy.mjs +1 -1
- package/api/template/copy/copy.test.mjs +0 -9
- package/api/template/template-integration.test.mjs +65 -1
- package/api/template/template.doc.mjs +1 -2
- package/api/template/template.mjs +1 -1
- package/api/theme/add/add.mjs +25 -17
- package/api/theme/add/add.staging.test.mjs +23 -40
- package/api/theme/build/build.family.test.mjs +12 -7
- package/api/theme/build/build.mjs +18 -8
- package/api/theme/generateTonalPalette.doc.mjs +2 -1
- package/api/theme/listThemes.doc.mjs +1 -1
- package/api/theme/themeAdd.doc.mjs +10 -9
- package/api/theme/themeBuild.doc.mjs +13 -13
- package/api/theme/themeList.doc.mjs +1 -1
- package/api/theme/themeListAvailable.doc.mjs +1 -2
- package/api/theme/themePaletteGenerate.doc.mjs +8 -15
- package/api/theme/themeTargets.doc.mjs +2 -3
- package/api/theme/themeTemplate.doc.mjs +1 -2
- package/api/upgrade/run/run.mjs +4 -6
- package/api/upgrade/upgrade.doc.mjs +22 -24
- package/api/upgrade/upgrade.type.mjs +2 -2
- package/assets/codemods/__tests__/runner.test.mjs +1 -3
- package/assets/codemods/integration-runner.mjs +3 -3
- package/assets/codemods/runner.mjs +4 -5
- package/assets/docs/README.md +2 -4
- package/assets/docs/browser-support.doc.mjs +11 -11
- package/assets/docs/color.doc.mjs +2 -8
- package/assets/docs/elevation.doc.mjs +4 -6
- package/assets/docs/getting-started.doc.mjs +16 -5
- package/assets/docs/icons.doc.mjs +21 -2
- package/assets/docs/illustrations.doc.mjs +15 -7
- package/assets/docs/internationalization.doc.mjs +5 -7
- package/assets/docs/layout.doc.dense.mjs +82 -130
- package/assets/docs/layout.doc.mjs +77 -133
- package/assets/docs/migration.doc.mjs +21 -19
- package/assets/docs/motion.doc.mjs +3 -16
- package/assets/docs/principles.doc.dense.mjs +5 -5
- package/assets/docs/principles.doc.mjs +0 -8
- package/assets/docs/principles.doc.zh.mjs +6 -6
- package/assets/docs/shape.doc.mjs +3 -8
- package/assets/docs/spacing.doc.mjs +2 -7
- package/assets/docs/styling-libraries.doc.mjs +2 -6
- package/assets/docs/styling.doc.mjs +23 -19
- package/assets/docs/theme.doc.dense.mjs +18 -58
- package/assets/docs/theme.doc.mjs +46 -56
- package/assets/docs/theme.doc.zh.mjs +8 -9
- package/assets/docs/tokens.doc.dense.mjs +2 -2
- package/assets/docs/tokens.doc.mjs +8 -389
- package/assets/docs/tokens.doc.zh.mjs +2 -2
- package/assets/docs/tree/integrations.doc.mjs +451 -25
- package/assets/docs/tree/integrations.test.mjs +62 -0
- package/assets/docs/tree/writing-docs.doc.mjs +286 -0
- package/assets/docs/typography.doc.mjs +4 -24
- package/assets/docs/working-with-ai.doc.mjs +22 -30
- package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
- package/authoring/config/config.doc.mjs +2 -10
- package/authoring/config/parse.d.mts +0 -2
- package/authoring/config/parse.mjs +0 -19
- package/authoring/config/parse.test.mjs +0 -8
- package/authoring/config/type.ts +2 -13
- package/authoring/doctypes/_schema.d.mts +2 -3
- package/authoring/doctypes/_schema.mjs +0 -6
- package/authoring/doctypes/base/graph-fields.doc.mjs +3 -3
- package/authoring/doctypes/base/type.ts +2 -4
- package/authoring/doctypes/command/command.doc.mjs +1 -1
- package/authoring/doctypes/command/type.ts +1 -1
- package/authoring/doctypes/component/component.doc.mjs +0 -6
- package/authoring/doctypes/component/type.ts +0 -8
- package/authoring/doctypes/reference/reference.doc.mjs +0 -7
- package/authoring/doctypes/reference/type.ts +0 -5
- package/authoring/doctypes/schema/schema.doc.mjs +2 -2
- package/authoring/doctypes/template/template.doc.mjs +1 -1
- package/authoring/doctypes/template/type.ts +2 -2
- package/authoring/index.d.mts +0 -1
- package/authoring/index.d.ts +0 -10
- package/authoring/index.mjs +0 -1
- package/authoring/integration/integration.doc.mjs +10 -12
- package/clients/cli/command-result-coverage.test.mjs +7 -7
- package/clients/cli/commands/component/index.mjs +55 -152
- package/clients/cli/commands/component-ownership.test.mjs +0 -89
- package/clients/cli/commands/component.doc.mjs +9 -27
- package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
- package/clients/cli/commands/discover.doc.mjs +9 -53
- package/clients/cli/commands/discover.mjs +118 -393
- package/clients/cli/commands/docs.doc.mjs +1 -1
- package/clients/cli/commands/docs.mjs +17 -60
- package/clients/cli/commands/docs.test.mjs +294 -0
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +2 -3
- package/clients/cli/commands/doctor-integration.test.mjs +0 -53
- package/clients/cli/commands/doctor.doc.mjs +1 -3
- package/clients/cli/commands/doctor.mjs +5 -49
- package/clients/cli/commands/gap-report.doc.mjs +9 -10
- package/clients/cli/commands/init.doc.mjs +6 -9
- package/clients/cli/commands/integration-add.doc.mjs +9 -9
- package/clients/cli/commands/integration-authoring.test.mjs +10 -61
- package/clients/cli/commands/integration-pack.doc.mjs +9 -5
- package/clients/cli/commands/integration-real-world.test.mjs +1 -1
- package/clients/cli/commands/integration.doc.mjs +4 -4
- package/clients/cli/commands/integration.mjs +43 -74
- package/clients/cli/commands/layout-check.doc.mjs +65 -0
- package/clients/cli/commands/layout-expand.doc.mjs +83 -0
- package/clients/cli/commands/layout-grammar.doc.mjs +30 -0
- package/clients/cli/commands/layout.doc.mjs +34 -0
- package/clients/cli/commands/layout.error-codes.test.mjs +66 -0
- package/clients/cli/commands/layout.exit-parity.test.mjs +41 -0
- package/clients/cli/commands/layout.mjs +275 -0
- package/clients/cli/commands/layout.path-help.test.mjs +33 -0
- package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
- package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/search.doc.mjs +3 -10
- package/clients/cli/commands/search.mjs +2 -21
- package/clients/cli/commands/search.test.mjs +4 -21
- package/clients/cli/commands/swizzle.doc.mjs +1 -1
- package/clients/cli/commands/template.doc.mjs +1 -1
- package/clients/cli/commands/text-json-parity.test.mjs +16 -5
- package/clients/cli/commands/theme-add.doc.mjs +1 -1
- package/clients/cli/commands/theme-palette-generate.doc.mjs +2 -3
- package/clients/cli/commands/theme-palette.doc.mjs +2 -1
- package/clients/cli/commands/theme-targets.doc.mjs +2 -2
- package/clients/cli/commands/theme.doc.mjs +1 -2
- package/clients/cli/commands/upgrade.doc.mjs +3 -62
- package/clients/cli/index.mjs +10 -28
- package/clients/cli/lib/define-command.mjs +4 -28
- package/clients/cli/lib/define-command.test.mjs +0 -54
- package/clients/cli/lib/exit-codes.test.mjs +9 -18
- package/clients/cli/lib/json-shim.mjs +14 -24
- package/clients/cli/lib/json-shim.test.mjs +20 -6
- package/clients/cli/lib/manifest.mjs +13 -18
- package/clients/cli/lib/manifest.test.mjs +2 -5
- package/foundation/agent-docs/agent-docs.mjs +1 -1
- package/foundation/agent-docs/agent-docs.test.mjs +1159 -0
- package/foundation/discovery/authoring-self-docs.mjs +0 -1
- package/foundation/discovery/authoring-self-docs.test.mjs +2 -6
- package/foundation/discovery/cli-self-docs.mjs +2 -16
- package/foundation/discovery/cli-self-docs.test.mjs +0 -20
- package/foundation/discovery/docs-discovery.mjs +1 -5
- package/foundation/discovery/docs-discovery.test.mjs +0 -21
- package/foundation/discovery/docs-section-key.d.mts +1 -1
- package/foundation/discovery/docs-section-key.mjs +1 -1
- package/foundation/discovery/template-adapter.mjs +1 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +14 -3
- package/foundation/doc-compiler/tree.d.mts +0 -4
- package/foundation/doc-compiler/tree.mjs +1 -6
- package/foundation/doc-compiler/tree.test.mjs +598 -0
- package/foundation/integrations/cli-requirement.d.mts +6 -26
- package/foundation/integrations/cli-requirement.mjs +11 -46
- package/foundation/integrations/cli-requirement.test.mjs +2 -7
- package/foundation/integrations/contribution-inventory.mjs +1 -1
- package/foundation/integrations/integrations.d.mts +1 -14
- package/foundation/integrations/integrations.mjs +1 -41
- package/foundation/integrations/integrations.test.mjs +0 -31
- package/foundation/response/error-codes.doc.mjs +8 -6
- package/foundation/response/error-codes.test.mjs +5 -30
- package/foundation/response/response-types.doc.d.mts +3 -4
- package/foundation/response/response-types.doc.mjs +27 -40
- package/foundation/response/response-types.doc.test.mjs +0 -23
- package/foundation/response/response.doc.mjs +10 -11
- package/foundation/xle/browser.d.mts +3 -3
- package/foundation/xle/browser.mjs +3 -3
- package/foundation/xle/expand.mjs +2 -2
- package/foundation/xle/parse.mjs +1 -1
- package/foundation/xle/print.mjs +2 -2
- package/foundation/xle/splice.mjs +1 -1
- package/package.json +9 -9
- package/api/discover/_adapter.test.mjs +0 -215
- package/api/discover/_catalog-view.d.mts +0 -115
- package/api/discover/_catalog-view.mjs +0 -203
- package/api/discover/_catalog-view.test.mjs +0 -128
- package/api/discover/detail/item/item.d.mts +0 -26
- package/api/discover/detail/item/item.mjs +0 -78
- package/api/discover/detail/item/item.test.mjs +0 -73
- package/api/integration/pack-check.lifecycle-output.test.mjs +0 -107
- package/api/theme/add/add.rollback.test.mjs +0 -158
- package/api/theme/build/build.rollback.test.mjs +0 -148
- package/api/upgrade/run/files-changed.test.mjs +0 -111
- package/assets/codemods/file-count.test.mjs +0 -163
- package/assets/docs/tree/add-a-component.doc.mjs +0 -75
- package/assets/docs/tree/add-a-theme.doc.mjs +0 -85
- package/assets/docs/tree/add-a-topic.doc.mjs +0 -144
- package/assets/docs/tree/agent-guidance.doc.mjs +0 -138
- package/assets/docs/tree/block-template.doc.mjs +0 -130
- package/assets/docs/tree/build-the-template.doc.mjs +0 -28
- package/assets/docs/tree/building-blocks.doc.mjs +0 -46
- package/assets/docs/tree/check-your-docs.doc.mjs +0 -137
- package/assets/docs/tree/checks.doc.mjs +0 -119
- package/assets/docs/tree/codemods.doc.mjs +0 -147
- package/assets/docs/tree/component-family.doc.mjs +0 -113
- package/assets/docs/tree/component-imports.doc.mjs +0 -69
- package/assets/docs/tree/component-lookups.doc.mjs +0 -149
- package/assets/docs/tree/components.doc.mjs +0 -23
- package/assets/docs/tree/configuration.doc.mjs +0 -23
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +0 -182
- package/assets/docs/tree/define-the-theme.doc.mjs +0 -118
- package/assets/docs/tree/describe-the-component.doc.mjs +0 -57
- package/assets/docs/tree/docs.doc.mjs +0 -21
- package/assets/docs/tree/document-the-template.doc.mjs +0 -28
- package/assets/docs/tree/document-the-theme.doc.mjs +0 -68
- package/assets/docs/tree/export-template-assets.doc.mjs +0 -147
- package/assets/docs/tree/extend-or-replace.doc.mjs +0 -103
- package/assets/docs/tree/fonts-and-assets.doc.mjs +0 -106
- package/assets/docs/tree/generate-a-palette.doc.mjs +0 -66
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +0 -105
- package/assets/docs/tree/help.doc.mjs +0 -16
- package/assets/docs/tree/links.doc.mjs +0 -98
- package/assets/docs/tree/package-and-test.doc.mjs +0 -32
- package/assets/docs/tree/page-template.doc.mjs +0 -71
- package/assets/docs/tree/publishing.doc.mjs +0 -111
- package/assets/docs/tree/quick-start.doc.mjs +0 -272
- package/assets/docs/tree/replace-a-core-component.doc.mjs +0 -104
- package/assets/docs/tree/replace-a-core-template.doc.mjs +0 -172
- package/assets/docs/tree/sections-and-placement.doc.mjs +0 -108
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +0 -59
- package/assets/docs/tree/ship.doc.mjs +0 -16
- package/assets/docs/tree/short-and-findable.doc.mjs +0 -108
- package/assets/docs/tree/single-component.doc.mjs +0 -165
- package/assets/docs/tree/start-a-template.doc.mjs +0 -143
- package/assets/docs/tree/subcomponent.doc.mjs +0 -115
- package/assets/docs/tree/template-assets.doc.mjs +0 -64
- package/assets/docs/tree/template-doc-overview.doc.mjs +0 -109
- package/assets/docs/tree/template-fonts.doc.mjs +0 -102
- package/assets/docs/tree/template-grading-rubric.doc.mjs +0 -452
- package/assets/docs/tree/template-icons.doc.mjs +0 -97
- package/assets/docs/tree/template-images-media.doc.mjs +0 -127
- package/assets/docs/tree/template-styles.doc.mjs +0 -93
- package/assets/docs/tree/templates.doc.mjs +0 -34
- package/assets/docs/tree/test-in-an-app.doc.mjs +0 -115
- package/assets/docs/tree/test-template-in-app.doc.mjs +0 -128
- package/assets/docs/tree/themes.doc.mjs +0 -39
- package/assets/docs/tree/troubleshooting.doc.mjs +0 -149
- package/assets/docs/tree/upgrading.doc.mjs +0 -103
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +0 -51
- package/assets/docs/tree/verify-packed-template.doc.mjs +0 -77
- package/assets/docs/tree/versioning.doc.mjs +0 -161
- package/assets/docs/tree/write-good-templates.doc.mjs +0 -64
- package/assets/docs/tree/write-the-template-file.doc.mjs +0 -154
- package/authoring/discover/discover.doc.d.mts +0 -13
- package/authoring/discover/discover.doc.mjs +0 -138
- package/authoring/discover/parse.d.mts +0 -24
- package/authoring/discover/parse.mjs +0 -128
- package/authoring/discover/parse.test.mjs +0 -124
- package/authoring/discover/type.ts +0 -87
- package/clients/cli/commands/component-batch.test.mjs +0 -341
- package/clients/cli/commands/discover.sources.test.mjs +0 -267
- package/clients/cli/commands/integration-verify.doc.mjs +0 -22
- package/clients/cli/lib/parse-error-format.test.mjs +0 -81
- package/foundation/response/batch.type.d.mts +0 -33
- package/foundation/response/batch.type.mjs +0 -34
|
@@ -7,13 +7,13 @@ export const doc = {
|
|
|
7
7
|
name: 'integrationPackCheck',
|
|
8
8
|
namespace: 'cli/api',
|
|
9
9
|
displayName: 'integrationPackCheck()',
|
|
10
|
-
summary: '
|
|
10
|
+
summary: 'Prove an integration package survives npm packing.',
|
|
11
11
|
description:
|
|
12
12
|
"Validates the local integration, runs the package lifecycle, packs with npm, checks required files against npm's authoritative tarball list, extracts the real tarball into a scratch consumer, compares local and packed contribution inventories, and resolves every packed component through its documented public import to verify that module exports the component. A package that ships a namespace doc or a placed guide, or has a template that sets `replaces`, fails unless its `@astryxdesign/cli` peer range admits only CLIs that read them.",
|
|
13
13
|
importPath: '@astryxdesign/cli/api',
|
|
14
14
|
signature:
|
|
15
15
|
'integrationPackCheck(options?: IntegrationPackCheckOptions): Promise<IntegrationPackCheckResponse>',
|
|
16
|
-
keywords: ['
|
|
16
|
+
keywords: ['integration', 'pack', 'check', 'publish', 'tarball', 'consumer'],
|
|
17
17
|
params: [
|
|
18
18
|
{
|
|
19
19
|
name: 'options.cwd',
|
|
@@ -31,6 +31,6 @@ export const doc = {
|
|
|
31
31
|
examples: [
|
|
32
32
|
{label: 'Check the local package', code: 'await integrationPackCheck();'},
|
|
33
33
|
],
|
|
34
|
-
command: 'integration
|
|
34
|
+
command: 'integration pack',
|
|
35
35
|
related: ['integrationAdd', 'validateIntegration'],
|
|
36
36
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @file `astryx integration
|
|
4
|
+
* @file `astryx integration pack --check` — verify an integration package is
|
|
5
5
|
* ready to publish by cross-referencing its declared contributions against the
|
|
6
6
|
* real npm tarball.
|
|
7
7
|
*
|
|
@@ -30,13 +30,8 @@ import {resolvePackageDir} from '../../foundation/integrations/integrations.mjs'
|
|
|
30
30
|
import {
|
|
31
31
|
docsTreeCliProblem,
|
|
32
32
|
replacesCliProblem,
|
|
33
|
-
sectionIdsCliProblem,
|
|
34
|
-
themesCliProblem,
|
|
35
33
|
} from '../../foundation/integrations/cli-requirement.mjs';
|
|
36
|
-
import {
|
|
37
|
-
discoverIntegrationDocs,
|
|
38
|
-
loadTopicModule,
|
|
39
|
-
} from '../../foundation/discovery/docs-discovery.mjs';
|
|
34
|
+
import {discoverIntegrationDocs} from '../../foundation/discovery/docs-discovery.mjs';
|
|
40
35
|
import {
|
|
41
36
|
discoverIntegrationComponents,
|
|
42
37
|
resolveIntegrationImportPath,
|
|
@@ -167,22 +162,6 @@ export function parseNpmPackOutput(output) {
|
|
|
167
162
|
};
|
|
168
163
|
}
|
|
169
164
|
|
|
170
|
-
/**
|
|
171
|
-
* Summarize the JSON error npm prints on stdout when `--json` pack fails.
|
|
172
|
-
* @param {string} output
|
|
173
|
-
* @returns {string}
|
|
174
|
-
*/
|
|
175
|
-
function npmPackErrorDetail(output) {
|
|
176
|
-
try {
|
|
177
|
-
const error = JSON.parse(output)?.error;
|
|
178
|
-
return [error?.summary, error?.detail]
|
|
179
|
-
.filter(part => typeof part === 'string' && part.trim() !== '')
|
|
180
|
-
.join(': ');
|
|
181
|
-
} catch {
|
|
182
|
-
return (output || '').trim();
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
165
|
/**
|
|
187
166
|
* Run `npm pack --json` with output directed to `destDir` so no preexisting
|
|
188
167
|
* tgz is overwritten. This intentionally runs the package lifecycle, matching
|
|
@@ -196,25 +175,16 @@ function npmPackErrorDetail(output) {
|
|
|
196
175
|
function runNpmPack(packageDir, destDir) {
|
|
197
176
|
const result = spawnSync(
|
|
198
177
|
'npm',
|
|
199
|
-
[
|
|
200
|
-
'pack',
|
|
201
|
-
'--json',
|
|
202
|
-
'--silent',
|
|
203
|
-
// Lifecycle scripts still run; background mode keeps their output off
|
|
204
|
-
// the stdout that carries the JSON result.
|
|
205
|
-
'--foreground-scripts=false',
|
|
206
|
-
`--pack-destination=${destDir}`,
|
|
207
|
-
],
|
|
178
|
+
['pack', '--json', '--silent', `--pack-destination=${destDir}`],
|
|
208
179
|
{cwd: packageDir, encoding: 'utf-8', timeout: 60_000},
|
|
209
180
|
);
|
|
210
181
|
if (result.error) {
|
|
211
182
|
throw new Error(`Could not start npm pack: ${result.error.message}`);
|
|
212
183
|
}
|
|
213
184
|
if (result.status !== 0) {
|
|
214
|
-
const
|
|
215
|
-
(result.stderr || '').trim() || npmPackErrorDetail(result.stdout);
|
|
185
|
+
const stderr = (result.stderr || '').trim();
|
|
216
186
|
throw new Error(
|
|
217
|
-
`npm pack failed (exit ${result.status})${
|
|
187
|
+
`npm pack failed (exit ${result.status})${stderr ? `: ${stderr}` : ''}.`,
|
|
218
188
|
);
|
|
219
189
|
}
|
|
220
190
|
return parseNpmPackOutput(result.stdout);
|
|
@@ -338,23 +308,6 @@ function moduleExportsName(file, exportName, seen = new Set()) {
|
|
|
338
308
|
return found;
|
|
339
309
|
}
|
|
340
310
|
|
|
341
|
-
/**
|
|
342
|
-
* Whether any of these doc files has a section that sets `id`.
|
|
343
|
-
* @param {string[]} files
|
|
344
|
-
* @returns {Promise<boolean>}
|
|
345
|
-
*/
|
|
346
|
-
async function setsSectionIds(files) {
|
|
347
|
-
for (const file of files) {
|
|
348
|
-
if (typeof file !== 'string') continue;
|
|
349
|
-
const doc = /** @type {any} */ (await loadTopicModule(file).catch(() => null));
|
|
350
|
-
const sections = Array.isArray(doc?.sections) ? doc.sections : [];
|
|
351
|
-
if (sections.some((/** @type {any} */ section) => section?.id != null)) {
|
|
352
|
-
return true;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
return false;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
311
|
/**
|
|
359
312
|
* Resolve package specifiers through Node's real ESM resolver from the scratch
|
|
360
313
|
* consumer. Resolution does not execute the target module, so source `.tsx`
|
|
@@ -647,31 +600,19 @@ export async function integrationPackCheck(options = {}) {
|
|
|
647
600
|
// (spec:AST-046 FR11): an older CLI can hide every doc topic the package
|
|
648
601
|
// ships, so the declared CLI range must admit only CLIs that read it.
|
|
649
602
|
if (loaded.docs) {
|
|
650
|
-
const {
|
|
651
|
-
|
|
652
|
-
)
|
|
603
|
+
const {namespaces, guides} = await discoverIntegrationDocs(loaded).catch(
|
|
604
|
+
() => ({namespaces: [], guides: []}),
|
|
605
|
+
);
|
|
653
606
|
const problem =
|
|
654
607
|
namespaces.length > 0 || guides.length > 0
|
|
655
608
|
? docsTreeCliProblem(pkg)
|
|
656
609
|
: null;
|
|
657
610
|
if (problem != null) {
|
|
658
611
|
issues.push(error('docs_tree_needs_cli', problem));
|
|
659
|
-
} else if (
|
|
660
|
-
await setsSectionIds([
|
|
661
|
-
...records.map(record => record.path),
|
|
662
|
-
...guides.map(guide => /** @type {any} */ (guide.ref).topicFile),
|
|
663
|
-
])
|
|
664
|
-
) {
|
|
665
|
-
// A section `id` is also a field an older CLI rejects, hiding the
|
|
666
|
-
// package's doc topics; the same peer range fixes both.
|
|
667
|
-
const idProblem = sectionIdsCliProblem(pkg);
|
|
668
|
-
if (idProblem != null) {
|
|
669
|
-
issues.push(error('section_ids_need_cli', idProblem));
|
|
670
|
-
}
|
|
671
612
|
}
|
|
672
613
|
}
|
|
673
614
|
// A template that sets `replaces` needs a CLI that reads the field
|
|
674
|
-
// (spec:AST-035): an older CLI
|
|
615
|
+
// (spec:AST-035): an older CLI withholds the package's templates and docs.
|
|
675
616
|
if (loaded.templates) {
|
|
676
617
|
const found = await discoverIntegrationTemplatesForOne(loaded).catch(
|
|
677
618
|
() => ({templates: [], errors: []}),
|
|
@@ -684,12 +625,6 @@ export async function integrationPackCheck(options = {}) {
|
|
|
684
625
|
const problem = setsReplaces ? replacesCliProblem(pkg) : null;
|
|
685
626
|
if (problem != null) issues.push(error('replaces_needs_cli', problem));
|
|
686
627
|
}
|
|
687
|
-
// A theme needs a CLI that reads typed theme descriptors: an older CLI
|
|
688
|
-
// rejects the themes root and withholds the package's themes and docs.
|
|
689
|
-
if (localIdentities.themes.length > 0) {
|
|
690
|
-
const problem = themesCliProblem(pkg);
|
|
691
|
-
if (problem != null) issues.push(error('themes_need_cli', problem));
|
|
692
|
-
}
|
|
693
628
|
|
|
694
629
|
// Temp resources — always cleaned up
|
|
695
630
|
const tgzTmpDir = fs.mkdtempSync(
|
|
@@ -722,14 +657,6 @@ export async function integrationPackCheck(options = {}) {
|
|
|
722
657
|
// package's already-installed dependencies. The unique suffix makes
|
|
723
658
|
// concurrent checks independent.
|
|
724
659
|
scratchBase = fs.mkdtempSync(path.join(packageDir, '.astryx-pack-check-'));
|
|
725
|
-
// The consumer's own package.json makes it the package scope for its
|
|
726
|
-
// imports. Without one, Node resolves the package's name through the
|
|
727
|
-
// SOURCE package.json (self-reference), so an export target left out of
|
|
728
|
-
// the tarball would still resolve.
|
|
729
|
-
fs.writeFileSync(
|
|
730
|
-
path.join(scratchBase, 'package.json'),
|
|
731
|
-
`${JSON.stringify({name: 'astryx-verify-consumer', private: true})}\n`,
|
|
732
|
-
);
|
|
733
660
|
|
|
734
661
|
// Cross-reference file inventory vs pack list
|
|
735
662
|
if (!packResult.packedPaths.has(fileInv.manifest)) {
|
|
@@ -36,8 +36,6 @@ function writePackage({
|
|
|
36
36
|
scripts,
|
|
37
37
|
} = {}) {
|
|
38
38
|
const pkg = {name, version};
|
|
39
|
-
// A theme needs a CLI that reads typed theme descriptors.
|
|
40
|
-
if (themes) pkg.peerDependencies = {'@astryxdesign/cli': '>=0.7.0'};
|
|
41
39
|
if (files !== undefined) pkg.files = files;
|
|
42
40
|
if (scripts !== undefined) pkg.scripts = scripts;
|
|
43
41
|
fs.writeFileSync(
|
|
@@ -96,30 +94,6 @@ describe('integrationPackCheck', () => {
|
|
|
96
94
|
);
|
|
97
95
|
});
|
|
98
96
|
|
|
99
|
-
it('fails a package that ships a theme on a CLI range that cannot read it', async () => {
|
|
100
|
-
writePackage({files: ['astryx.integration.mjs', 'themes']});
|
|
101
|
-
const pkgFile = path.join(tmpDir, 'package.json');
|
|
102
|
-
const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
|
|
103
|
-
delete pkg.peerDependencies;
|
|
104
|
-
fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
105
|
-
|
|
106
|
-
const missing = await integrationPackCheck({cwd: tmpDir});
|
|
107
|
-
expect(missing.data.packable).toBe(false);
|
|
108
|
-
expect(missing.data.issues).toContainEqual(
|
|
109
|
-
expect.objectContaining({
|
|
110
|
-
code: 'themes_need_cli',
|
|
111
|
-
message: expect.stringContaining('ships a theme'),
|
|
112
|
-
}),
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
pkg.peerDependencies = {'@astryxdesign/cli': '^0.6.3'};
|
|
116
|
-
fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
117
|
-
const old = await integrationPackCheck({cwd: tmpDir});
|
|
118
|
-
expect(old.data.issues).toContainEqual(
|
|
119
|
-
expect.objectContaining({code: 'themes_need_cli'}),
|
|
120
|
-
);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
97
|
it('fails when a theme entry omits its inferred runtime export', async () => {
|
|
124
98
|
writePackage({files: ['astryx.integration.mjs', 'themes']});
|
|
125
99
|
fs.writeFileSync(
|
|
@@ -219,39 +193,6 @@ describe('integrationPackCheck', () => {
|
|
|
219
193
|
);
|
|
220
194
|
});
|
|
221
195
|
|
|
222
|
-
it('resolves public imports in the packed package, not the source', async () => {
|
|
223
|
-
// The root export's target is left out of `files`: the source package
|
|
224
|
-
// resolves it, but an app that installs the tarball cannot.
|
|
225
|
-
fs.writeFileSync(
|
|
226
|
-
path.join(tmpDir, 'package.json'),
|
|
227
|
-
`${JSON.stringify({
|
|
228
|
-
name: '@acme/widgets',
|
|
229
|
-
version: '1.0.0',
|
|
230
|
-
files: ['astryx.integration.mjs'],
|
|
231
|
-
exports: {'.': './index.mjs'},
|
|
232
|
-
})}\n`,
|
|
233
|
-
);
|
|
234
|
-
fs.writeFileSync(
|
|
235
|
-
path.join(tmpDir, 'index.mjs'),
|
|
236
|
-
"export {AcmeWidget} from './components/AcmeWidget.tsx';\n",
|
|
237
|
-
);
|
|
238
|
-
await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
|
|
239
|
-
const docFile = path.join(tmpDir, 'components', 'AcmeWidget.doc.mjs');
|
|
240
|
-
const doc = fs.readFileSync(docFile, 'utf-8');
|
|
241
|
-
expect(doc).toContain('@acme/widgets/components/AcmeWidget');
|
|
242
|
-
fs.writeFileSync(
|
|
243
|
-
docFile,
|
|
244
|
-
doc.replace('@acme/widgets/components/AcmeWidget', '@acme/widgets'),
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
const result = await integrationPackCheck({cwd: tmpDir});
|
|
248
|
-
|
|
249
|
-
expect(result.data.packable).toBe(false);
|
|
250
|
-
expect(result.data.issues).toContainEqual(
|
|
251
|
-
expect.objectContaining({code: 'component_export_missing'}),
|
|
252
|
-
);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
196
|
it('fails when packed template source is hidden by package exports', async () => {
|
|
256
197
|
writePackage({
|
|
257
198
|
manifest: "export default {templates: './templates'};\n",
|
|
@@ -395,37 +336,6 @@ describe('integrationPackCheck', () => {
|
|
|
395
336
|
expect(await codes()).not.toContain('docs_tree_needs_cli');
|
|
396
337
|
}, 120_000);
|
|
397
338
|
|
|
398
|
-
it('fails a package whose doc section sets id on a CLI range that rejects the field', async () => {
|
|
399
|
-
writePackage({manifest: "export default {docs: './docs'};\n", themes: false});
|
|
400
|
-
fs.mkdirSync(path.join(tmpDir, 'docs'), {recursive: true});
|
|
401
|
-
const topic = (/** @type {string} */ section) =>
|
|
402
|
-
`export default {type: 'generic', name: 'notes', title: 'Notes', description: 'Notes.', sections: [${section}]};\n`;
|
|
403
|
-
const file = path.join(tmpDir, 'docs', 'notes.doc.mjs');
|
|
404
|
-
const codes = async () =>
|
|
405
|
-
(await integrationPackCheck({cwd: tmpDir})).data.issues.map(
|
|
406
|
-
(/** @type {{code: string}} */ issue) => issue.code,
|
|
407
|
-
);
|
|
408
|
-
fs.writeFileSync(
|
|
409
|
-
file,
|
|
410
|
-
topic("{title: 'Take notes', content: [{type: 'prose', text: 'Notes.'}]}"),
|
|
411
|
-
);
|
|
412
|
-
expect(await codes()).not.toContain('section_ids_need_cli');
|
|
413
|
-
// A fresh file name: the module loader caches a path once it is imported.
|
|
414
|
-
fs.rmSync(file);
|
|
415
|
-
fs.writeFileSync(
|
|
416
|
-
path.join(tmpDir, 'docs', 'notes-with-ids.doc.mjs'),
|
|
417
|
-
topic(
|
|
418
|
-
"{id: 'take-notes', title: 'Take notes', content: [{type: 'prose', text: 'Notes.'}]}",
|
|
419
|
-
),
|
|
420
|
-
);
|
|
421
|
-
expect(await codes()).toContain('section_ids_need_cli');
|
|
422
|
-
const pkgFile = path.join(tmpDir, 'package.json');
|
|
423
|
-
const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
|
|
424
|
-
pkg.peerDependencies = {'@astryxdesign/cli': '>=0.7.0'};
|
|
425
|
-
fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
426
|
-
expect(await codes()).not.toContain('section_ids_need_cli');
|
|
427
|
-
}, 120_000);
|
|
428
|
-
|
|
429
339
|
it('fails a package with a template that sets replaces on a CLI range that rejects the field', async () => {
|
|
430
340
|
writePackage({manifest: "export default {templates: './templates'};\n", themes: false});
|
|
431
341
|
fs.mkdirSync(path.join(tmpDir, 'templates'), {recursive: true});
|
|
@@ -49,7 +49,7 @@ export const doc = {
|
|
|
49
49
|
throws: [
|
|
50
50
|
{
|
|
51
51
|
code: 'Error',
|
|
52
|
-
when: '
|
|
52
|
+
when: 'the CLI returned an error envelope (the CLI message is rethrown), or the response `type` is not expectedType',
|
|
53
53
|
},
|
|
54
54
|
],
|
|
55
55
|
examples: [
|
package/api/json/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export type * from '../gap-report/gap-report.type.mjs';
|
|
|
26
26
|
export type * from '../upgrade/upgrade.type.mjs';
|
|
27
27
|
export type * from '../init/init.type.mjs';
|
|
28
28
|
export type * from '../doctor/doctor.type.mjs';
|
|
29
|
+
export type * from '../layout/layout.type.mjs';
|
|
29
30
|
export type * from '../integration/validate-integration.type.mjs';
|
|
30
31
|
export type * from '../integration/authoring-checks.type.mjs';
|
|
31
32
|
export type * from '../integration/pack-check.type.mjs';
|
package/api/json/isError.doc.mjs
CHANGED
|
@@ -15,7 +15,7 @@ export const doc = {
|
|
|
15
15
|
displayName: 'isError()',
|
|
16
16
|
summary: 'Did the CLI return an error envelope?',
|
|
17
17
|
description:
|
|
18
|
-
'Tests a parsed response for an `error` key. Branch on this before touching `data
|
|
18
|
+
'Tests a parsed response for an `error` key. Branch on this before touching `data`: ' +
|
|
19
19
|
'and prefer the stable `code` field over matching the human-readable message, which is ' +
|
|
20
20
|
'not a contract. Note this returns a plain boolean, not a TypeScript type predicate, so ' +
|
|
21
21
|
'it does not narrow on its own: cast to the matching *Response type to get typed access.',
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/** @param {import('../../foundation/xle/xle-ast').RawIssue} issue */
|
|
5
|
+
export function formatIssue(issue: import("../../foundation/xle/xle-ast").RawIssue): string;
|
|
6
|
+
/**
|
|
7
|
+
* Parse + validate, throwing structured XDSErrors on failure.
|
|
8
|
+
* Returns {doc, registry, blocks, warnings}.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} expression
|
|
11
|
+
* @param {{form?: 'compact'|'outline'|'auto', loose?: boolean, cwd?: string}} [options]
|
|
12
|
+
*/
|
|
13
|
+
export function analyze(expression: string, { form, loose, cwd }?: {
|
|
14
|
+
form?: "compact" | "outline" | "auto";
|
|
15
|
+
loose?: boolean;
|
|
16
|
+
cwd?: string;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
doc: import("../../foundation/xle/xle-ast").XLEDoc;
|
|
19
|
+
registry: import("../../foundation/xle/xle-ast").Registry;
|
|
20
|
+
blocks: LayoutBlock[];
|
|
21
|
+
errors: import("../../foundation/xle/xle-ast").RawIssue[];
|
|
22
|
+
warnings: import("../../foundation/xle/xle-ast").RawIssue[];
|
|
23
|
+
}>;
|
|
24
|
+
export type LayoutBlock = {
|
|
25
|
+
dirName: string;
|
|
26
|
+
name: string;
|
|
27
|
+
kind: "template" | "component";
|
|
28
|
+
type?: string | undefined;
|
|
29
|
+
description?: string | undefined;
|
|
30
|
+
category?: string | undefined;
|
|
31
|
+
importPath?: string | undefined;
|
|
32
|
+
filePath?: string | undefined;
|
|
33
|
+
isDefault?: boolean | undefined;
|
|
34
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Shared analysis layer for the `layout` command's expand/check leaves.
|
|
5
|
+
*
|
|
6
|
+
* Loads the block catalog (template blocks + app-registered components), builds
|
|
7
|
+
* the branch registry, and parses+validates a layout expression into a doc +
|
|
8
|
+
* issues. Both the expand and check leaves sit on `analyze`; neither parses or
|
|
9
|
+
* validates directly. (The grammar leaf needs none of this — it only reads the
|
|
10
|
+
* registry alias table.)
|
|
11
|
+
*
|
|
12
|
+
* @input expression string (+ options)
|
|
13
|
+
* @output analyze() -> {doc, registry, blocks, errors, warnings}; formatIssue()
|
|
14
|
+
* @position api — shared core over lib/xle; leaves in expand/ + check/ project it
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {AstryxError} from '../error.mjs';
|
|
18
|
+
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
19
|
+
import {parse, XLEParseError} from '../../foundation/xle/parse.mjs';
|
|
20
|
+
import {validate} from '../../foundation/xle/validate.mjs';
|
|
21
|
+
import {buildRegistry} from '../../foundation/xle/registry.mjs';
|
|
22
|
+
import {discoverTemplates} from '../template/template.mjs';
|
|
23
|
+
import {Project} from '../../foundation/config/project.mjs';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {object} LayoutBlock
|
|
27
|
+
* @property {string} dirName
|
|
28
|
+
* @property {string} name
|
|
29
|
+
* @property {'template'|'component'} kind
|
|
30
|
+
* @property {string} [type]
|
|
31
|
+
* @property {string} [description]
|
|
32
|
+
* @property {string} [category]
|
|
33
|
+
* @property {string} [importPath]
|
|
34
|
+
* @property {string} [filePath]
|
|
35
|
+
* @property {boolean} [isDefault]
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The catalog a `{hint}` can resolve to: template blocks (spliced inline) plus
|
|
40
|
+
* any app-registered local components from astryx.config.mjs
|
|
41
|
+
* `experimental.xle.components` (imported by name). App components are how XLE
|
|
42
|
+
* reaches domain pieces — the KpiCard/chart/drawer set that the
|
|
43
|
+
* @astryxdesign/core registry can't see.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} cwd
|
|
46
|
+
* @returns {Promise<LayoutBlock[]>}
|
|
47
|
+
*/
|
|
48
|
+
async function loadBlocks(cwd) {
|
|
49
|
+
/** @type {LayoutBlock[]} */
|
|
50
|
+
const blocks = [];
|
|
51
|
+
try {
|
|
52
|
+
const all = await discoverTemplates(cwd);
|
|
53
|
+
const templates = all.filter(template => template.type === 'block');
|
|
54
|
+
/** @type {Map<string, import('../../foundation/discovery/template-adapter.mjs').DiscoveredTemplate>} */
|
|
55
|
+
const byId = new Map();
|
|
56
|
+
// Exact ids are the fallback. Active replacement aliases override them in a
|
|
57
|
+
// second pass, matching template() regardless of discovery/display order.
|
|
58
|
+
for (const template of templates) byId.set(template.dirName, template);
|
|
59
|
+
for (const template of templates) {
|
|
60
|
+
if (template.replaces != null) byId.set(template.replaces, template);
|
|
61
|
+
}
|
|
62
|
+
for (const [id, template] of byId) {
|
|
63
|
+
blocks.push({...template, dirName: id, kind: 'template'});
|
|
64
|
+
}
|
|
65
|
+
} catch {
|
|
66
|
+
// discovery is best-effort
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const project = await Project.load(cwd);
|
|
70
|
+
/** @type {Record<string, {from?: string, description?: string, default?: boolean}>} */
|
|
71
|
+
const components = project.config.experimental?.xle?.components ?? {};
|
|
72
|
+
for (const [name, spec] of Object.entries(components)) {
|
|
73
|
+
const importPath = spec.from;
|
|
74
|
+
if (!importPath) continue;
|
|
75
|
+
blocks.push({
|
|
76
|
+
type: 'block',
|
|
77
|
+
kind: 'component',
|
|
78
|
+
dirName: name,
|
|
79
|
+
name,
|
|
80
|
+
description: spec.description ?? '',
|
|
81
|
+
category: 'app',
|
|
82
|
+
importPath,
|
|
83
|
+
isDefault: Boolean(spec.default),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
// config is optional
|
|
88
|
+
}
|
|
89
|
+
return blocks;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** @param {import('../../foundation/xle/xle-ast').RawIssue} issue */
|
|
93
|
+
export function formatIssue(issue) {
|
|
94
|
+
const where = issue.line != null ? `line ${issue.line}: ` : '';
|
|
95
|
+
return `${where}${issue.message}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Parse + validate, throwing structured XDSErrors on failure.
|
|
100
|
+
* Returns {doc, registry, blocks, warnings}.
|
|
101
|
+
*
|
|
102
|
+
* @param {string} expression
|
|
103
|
+
* @param {{form?: 'compact'|'outline'|'auto', loose?: boolean, cwd?: string}} [options]
|
|
104
|
+
*/
|
|
105
|
+
export async function analyze(
|
|
106
|
+
expression,
|
|
107
|
+
{form = 'auto', loose = false, cwd = process.cwd()} = {},
|
|
108
|
+
) {
|
|
109
|
+
// Validate inputs in the API (not just the CLI): an empty expression or an
|
|
110
|
+
// unknown --form must error, not silently parse as an empty/compact layout.
|
|
111
|
+
if (typeof expression !== 'string' || expression.trim() === '') {
|
|
112
|
+
throw new AstryxError(
|
|
113
|
+
'Layout expression is empty.',
|
|
114
|
+
undefined,
|
|
115
|
+
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (form !== 'compact' && form !== 'outline' && form !== 'auto') {
|
|
119
|
+
throw new AstryxError(
|
|
120
|
+
`Invalid form "${form}". Must be one of: compact, outline, auto.`,
|
|
121
|
+
undefined,
|
|
122
|
+
ERROR_CODES.ERR_INVALID_OPTION,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
const registry =
|
|
126
|
+
/** @type {import('../../foundation/xle/xle-ast').Registry} */ (
|
|
127
|
+
/** @type {unknown} */ (await buildRegistry({cwd}))
|
|
128
|
+
);
|
|
129
|
+
const blocks = await loadBlocks(cwd);
|
|
130
|
+
|
|
131
|
+
/** @type {import('../../foundation/xle/xle-ast').XLEDoc} */
|
|
132
|
+
let doc;
|
|
133
|
+
try {
|
|
134
|
+
doc = parse(expression, {form});
|
|
135
|
+
} catch (e) {
|
|
136
|
+
if (e instanceof XLEParseError) {
|
|
137
|
+
throw new AstryxError(
|
|
138
|
+
`Layout expression syntax error at line ${e.line}, col ${e.col}: ${e.message}`,
|
|
139
|
+
undefined,
|
|
140
|
+
ERROR_CODES.ERR_LAYOUT_PARSE,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
throw e;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const {errors, warnings} = validate(doc, registry, blocks, {loose});
|
|
147
|
+
return {doc, registry, blocks, errors, warnings};
|
|
148
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `astryx layout check "<expr>" [--form compact|outline]`
|
|
6
|
+
* Validates without expanding; echoes both canonical surfaces.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} expression
|
|
9
|
+
* @param {{form?: 'compact'|'outline'|'auto', loose?: boolean, cwd?: string}} [options]
|
|
10
|
+
* @returns {Promise<import('../layout.type.mjs').LayoutCheckResponse>}
|
|
11
|
+
*/
|
|
12
|
+
export function layoutCheck(expression: string, options?: {
|
|
13
|
+
form?: "compact" | "outline" | "auto";
|
|
14
|
+
loose?: boolean;
|
|
15
|
+
cwd?: string;
|
|
16
|
+
}): Promise<import("../layout.type.mjs").LayoutCheckResponse>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file `astryx layout check` leaf — validate a layout expression without
|
|
5
|
+
* expanding, echoing both canonical surfaces (compact + outline). Resolution +
|
|
6
|
+
* validation come from ../_adapter.mjs (analyze); this leaf projects the
|
|
7
|
+
* `layout.check` envelope.
|
|
8
|
+
*
|
|
9
|
+
* @input expression string (+ options)
|
|
10
|
+
* @output {type:'layout.check', data}
|
|
11
|
+
* @position api — leaf over ../_adapter.mjs + lib/xle/print
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {toCompact, toOutline} from '../../../foundation/xle/print.mjs';
|
|
15
|
+
import {analyze, formatIssue} from '../_adapter.mjs';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* `astryx layout check "<expr>" [--form compact|outline]`
|
|
19
|
+
* Validates without expanding; echoes both canonical surfaces.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} expression
|
|
22
|
+
* @param {{form?: 'compact'|'outline'|'auto', loose?: boolean, cwd?: string}} [options]
|
|
23
|
+
* @returns {Promise<import('../layout.type.mjs').LayoutCheckResponse>}
|
|
24
|
+
*/
|
|
25
|
+
export async function layoutCheck(expression, options = {}) {
|
|
26
|
+
const {form = 'auto', loose = false, cwd = process.cwd()} = options;
|
|
27
|
+
const {doc, errors, warnings} = await analyze(expression, {form, loose, cwd});
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
type: 'layout.check',
|
|
31
|
+
data: {
|
|
32
|
+
valid: errors.length === 0,
|
|
33
|
+
form: doc.form,
|
|
34
|
+
errors: errors.map(e => ({...e, formatted: formatIssue(e)})),
|
|
35
|
+
warnings: warnings.map(formatIssue),
|
|
36
|
+
compact: toCompact(doc),
|
|
37
|
+
outline: toOutline(doc),
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `astryx layout expand "<expr>" [path]`
|
|
6
|
+
*
|
|
7
|
+
* @param {string} expression
|
|
8
|
+
* @param {object} [options]
|
|
9
|
+
* @param {string} [options.targetPath] - write TSX here (validated against cwd)
|
|
10
|
+
* @param {'compact'|'outline'|'auto'} [options.form]
|
|
11
|
+
* @param {boolean} [options.loose] - downgrade unknown {hints} to TODO warnings
|
|
12
|
+
* @param {string} [options.name] - generated component name
|
|
13
|
+
* @param {string} [options.cwd]
|
|
14
|
+
* @returns {Promise<import('../layout.type.mjs').LayoutExpandResponse>}
|
|
15
|
+
*/
|
|
16
|
+
export function layoutExpand(expression: string, options?: {
|
|
17
|
+
targetPath?: string | undefined;
|
|
18
|
+
form?: "compact" | "auto" | "outline" | undefined;
|
|
19
|
+
loose?: boolean | undefined;
|
|
20
|
+
name?: string | undefined;
|
|
21
|
+
cwd?: string | undefined;
|
|
22
|
+
}): Promise<import("../layout.type.mjs").LayoutExpandResponse>;
|