@astryxdesign/cli 0.6.4-canary.9143f03 → 0.6.4-canary.9cc70a9
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 +6 -10
- package/api/index.d.mts +0 -2
- package/api/index.mjs +0 -2
- package/api/json/index.ts +0 -1
- package/api/template/template-integration.test.mjs +1 -65
- package/api/template/template.mjs +1 -1
- package/api/upgrade/run/run.mjs +1 -1
- package/authoring/config/config.doc.mjs +1 -1
- package/authoring/config/type.ts +2 -2
- package/authoring/doctypes/command/command.doc.mjs +1 -1
- package/authoring/doctypes/command/type.ts +1 -1
- package/clients/cli/command-result-coverage.test.mjs +7 -7
- package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
- package/clients/cli/commands/text-json-parity.test.mjs +0 -17
- package/clients/cli/index.mjs +0 -4
- package/clients/cli/lib/exit-codes.test.mjs +1 -8
- package/clients/cli/lib/json-shim.test.mjs +6 -20
- package/clients/cli/lib/manifest.mjs +0 -8
- package/foundation/discovery/template-adapter.mjs +1 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +0 -12
- package/foundation/response/response-types.doc.mjs +0 -17
- 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/layout/_adapter.d.mts +0 -34
- package/api/layout/_adapter.mjs +0 -148
- package/api/layout/check/check.d.mts +0 -16
- package/api/layout/check/check.mjs +0 -40
- package/api/layout/expand/expand.d.mts +0 -22
- package/api/layout/expand/expand.mjs +0 -155
- package/api/layout/expand/expand.path-safety.test.mjs +0 -53
- package/api/layout/grammar/grammar.d.mts +0 -13
- package/api/layout/grammar/grammar.mjs +0 -87
- package/api/layout/layout.d.mts +0 -6
- package/api/layout/layout.mjs +0 -17
- package/api/layout/layout.test.mjs +0 -297
- package/api/layout/layout.type.d.mts +0 -89
- package/api/layout/layout.type.mjs +0 -103
- package/api/layout/layoutCheck.doc.d.mts +0 -11
- package/api/layout/layoutCheck.doc.mjs +0 -85
- package/api/layout/layoutExpand.doc.d.mts +0 -11
- package/api/layout/layoutExpand.doc.mjs +0 -107
- package/api/layout/layoutGrammar.doc.d.mts +0 -11
- package/api/layout/layoutGrammar.doc.mjs +0 -57
- package/clients/cli/commands/layout-check.doc.mjs +0 -65
- package/clients/cli/commands/layout-expand.doc.mjs +0 -83
- package/clients/cli/commands/layout-grammar.doc.mjs +0 -30
- package/clients/cli/commands/layout.doc.mjs +0 -34
- package/clients/cli/commands/layout.error-codes.test.mjs +0 -66
- package/clients/cli/commands/layout.exit-parity.test.mjs +0 -41
- package/clients/cli/commands/layout.mjs +0 -275
- package/clients/cli/commands/layout.path-help.test.mjs +0 -33
- package/clients/cli/commands/layout.stdin-cap.test.mjs +0 -47
- package/clients/cli/commands/layout.text-fields.test.mjs +0 -39
package/README.md
CHANGED
|
@@ -89,7 +89,6 @@ Options:
|
|
|
89
89
|
| `hook` | List hooks or print hook docs |
|
|
90
90
|
| `init` | Initialize the design system in your project |
|
|
91
91
|
| `integration` | Author and verify an Astryx integration package |
|
|
92
|
-
| `layout` | Generate XDS layouts from compressed expressions (XLE/XLO) |
|
|
93
92
|
| `search` | Search components, hooks, docs, and templates in one ranked list |
|
|
94
93
|
| `swizzle` | Copy component source for customization |
|
|
95
94
|
| `template` | Inject a page or block template |
|
|
@@ -475,9 +474,6 @@ Every response has a `type` discriminant. The full set is below (generated from
|
|
|
475
474
|
| `integration.template-conflicts` | The integration identity, structural issues, and non-blocking Core template-id conflicts as {id, severity: warning, integrationPackage, integrationType, integrationName, coreMatches, message, command}. |
|
|
476
475
|
| `integration.component-conflicts` | The integration identity, structural issues, and non-blocking conflicts where an integration component name is also owned by Core; each conflict includes the exact package-qualified command. |
|
|
477
476
|
| `integration.doc-conflicts` | The integration identity, structural issues, and Core doc overlaps. Each finding includes `severity` (`info` \| `error`) and `relationship` (`replaces` \| `extends` \| `accidental`). |
|
|
478
|
-
| `layout.expand` | The expansion: parsed form, generated TSX code, componentsUsed, states (count of useState hooks scaffolded), todos, blocksReferenced (each {name, mode}), warnings, and written (the output path, or null when nothing was written). |
|
|
479
|
-
| `layout.check` | The validation result: a valid flag, the detected form, errors (each with line/col, message, formatted text, and suggestions), warnings, and the expression re-printed in both canonical surfaces (compact and outline). |
|
|
480
|
-
| `layout.grammar` | The XLE/XLO grammar cheatsheet: a text field with the full reference plus an aliases map (short name → canonical component) generated from this install's registry. |
|
|
481
477
|
|
|
482
478
|
<!-- END GENERATED: response-types -->
|
|
483
479
|
<!-- Generated by scripts/generate-cli-readme.mjs from the response-types EnumDoc. Run `pnpm -F @astryxdesign/cli readme`. -->
|
|
@@ -578,12 +574,12 @@ There is no factory: write a plain object. For editor autocomplete and
|
|
|
578
574
|
type-checking, annotate it with the `AstryxConfig` type exported from
|
|
579
575
|
`@astryxdesign/cli/authoring`.
|
|
580
576
|
|
|
581
|
-
| Field | Type | Purpose
|
|
582
|
-
| ----------------------------- | ------------------------------ |
|
|
583
|
-
| `integrations` | `string[]` | Integration package names to load (see [Integrations](#integrations)).
|
|
584
|
-
| `issuesUrl` | `string` | Where "report an issue" links point for your project. Defaults to the core issue tracker.
|
|
585
|
-
| `hooks.postCodemod` | `PostCodemodHook[]` | Commands to run after `astryx upgrade` applies codemods (e.g. reinstall, rebuild, reformat).
|
|
586
|
-
| `experimental.xle.components` | `Record<string, XleComponent>` |
|
|
577
|
+
| Field | Type | Purpose |
|
|
578
|
+
| ----------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
|
579
|
+
| `integrations` | `string[]` | Integration package names to load (see [Integrations](#integrations)). |
|
|
580
|
+
| `issuesUrl` | `string` | Where "report an issue" links point for your project. Defaults to the core issue tracker. |
|
|
581
|
+
| `hooks.postCodemod` | `PostCodemodHook[]` | Commands to run after `astryx upgrade` applies codemods (e.g. reinstall, rebuild, reformat). |
|
|
582
|
+
| `experimental.xle.components` | `Record<string, XleComponent>` | No effect. Its only reader was the removed `layout` command. Still accepted so existing configs keep loading; delete it. |
|
|
587
583
|
|
|
588
584
|
The config is validated against a strict schema when the CLI loads it, so an
|
|
589
585
|
unknown field is a hard error rather than a silent no-op. `astryx doctor`
|
package/api/index.d.mts
CHANGED
|
@@ -33,14 +33,12 @@ export * from "./gap-report/gap-report.type.mjs";
|
|
|
33
33
|
export * from "./upgrade/upgrade.type.mjs";
|
|
34
34
|
export * from "./init/init.type.mjs";
|
|
35
35
|
export * from "./doctor/doctor.type.mjs";
|
|
36
|
-
export * from "./layout/layout.type.mjs";
|
|
37
36
|
export * from "./integration/integration-authoring.type.mjs";
|
|
38
37
|
export * from "./integration/pack-check.type.mjs";
|
|
39
38
|
export * from "./integration/validate-integration.type.mjs";
|
|
40
39
|
export * from "./integration/authoring-checks.type.mjs";
|
|
41
40
|
export type Logger = import("./logger.mjs").Logger;
|
|
42
41
|
export { themeBuild, themeAdd, themeTemplate, themeList, themeListAvailable, themeTargets, themePaletteGenerate, generateTonalPalette, listThemes } from "./theme/theme.mjs";
|
|
43
|
-
export { layoutExpand, layoutCheck, layoutGrammar } from "./layout/layout.mjs";
|
|
44
42
|
export { integrationAdd, integrationAddAgentDoc, integrationAddCodemod, integrationAddComponent, integrationAddDoc, integrationAddTemplate } from "./integration/add-contribution.mjs";
|
|
45
43
|
export { validateIntegration, summarizeIssues } from "./integration/validate-integration.mjs";
|
|
46
44
|
export { integrationTemplateConflicts, integrationComponentConflicts, integrationDocConflicts } from "./integration/authoring-checks.mjs";
|
package/api/index.mjs
CHANGED
|
@@ -44,7 +44,6 @@ export {gapReport} from './gap-report/gap-report.mjs';
|
|
|
44
44
|
export {upgrade} from './upgrade/upgrade.mjs';
|
|
45
45
|
export {init} from './init/init.mjs';
|
|
46
46
|
export {doctor} from './doctor/doctor.mjs';
|
|
47
|
-
export {layoutExpand, layoutCheck, layoutGrammar} from './layout/layout.mjs';
|
|
48
47
|
export {
|
|
49
48
|
integrationAdd,
|
|
50
49
|
integrationAddAgentDoc,
|
|
@@ -93,7 +92,6 @@ export * from './gap-report/gap-report.type.mjs';
|
|
|
93
92
|
export * from './upgrade/upgrade.type.mjs';
|
|
94
93
|
export * from './init/init.type.mjs';
|
|
95
94
|
export * from './doctor/doctor.type.mjs';
|
|
96
|
-
export * from './layout/layout.type.mjs';
|
|
97
95
|
export * from './integration/integration-authoring.type.mjs';
|
|
98
96
|
export * from './integration/pack-check.type.mjs';
|
|
99
97
|
export * from './integration/validate-integration.type.mjs';
|
package/api/json/index.ts
CHANGED
|
@@ -26,7 +26,6 @@ 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';
|
|
30
29
|
export type * from '../integration/validate-integration.type.mjs';
|
|
31
30
|
export type * from '../integration/authoring-checks.type.mjs';
|
|
32
31
|
export type * from '../integration/pack-check.type.mjs';
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
} from './template.mjs';
|
|
20
20
|
import {search} from '../search/search.mjs';
|
|
21
21
|
import {build} from '../build/build.mjs';
|
|
22
|
-
import {layoutExpand} from '../layout/layout.mjs';
|
|
23
22
|
import {runCli} from '../../test-utils/run-cli.mjs';
|
|
24
23
|
|
|
25
24
|
let tmpDir;
|
|
@@ -518,53 +517,7 @@ describe('integration template discovery', () => {
|
|
|
518
517
|
});
|
|
519
518
|
});
|
|
520
519
|
|
|
521
|
-
it('resolves
|
|
522
|
-
const pkgDir = installWidgets(tmpDir);
|
|
523
|
-
writeTemplate(pkgDir, 'acme-card-callout', {
|
|
524
|
-
kind: 'block',
|
|
525
|
-
source:
|
|
526
|
-
'export default function AcmeCardCallout() { return <span>Acme replacement block</span>; }\n',
|
|
527
|
-
});
|
|
528
|
-
declareReplaces(pkgDir, {
|
|
529
|
-
'acme-card-callout': 'CardCallout',
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
const accidental = path.join(tmpDir, 'node_modules', '@acme', 'extra');
|
|
533
|
-
fs.mkdirSync(path.join(accidental, 'templates'), {recursive: true});
|
|
534
|
-
fs.writeFileSync(
|
|
535
|
-
path.join(accidental, 'package.json'),
|
|
536
|
-
JSON.stringify({name: '@acme/extra', version: '1.0.0'}),
|
|
537
|
-
);
|
|
538
|
-
fs.writeFileSync(
|
|
539
|
-
path.join(accidental, 'astryx.integration.mjs'),
|
|
540
|
-
`export default {templates: './templates'};\n`,
|
|
541
|
-
);
|
|
542
|
-
writeTemplate(accidental, 'CardCallout', {
|
|
543
|
-
kind: 'block',
|
|
544
|
-
body: `export default {type: 'block', name: 'ZZZ accidental block', description: 'collision'};\n`,
|
|
545
|
-
source:
|
|
546
|
-
'export default function Accidental() { return <span>Accidental block</span>; }\n',
|
|
547
|
-
});
|
|
548
|
-
fs.writeFileSync(
|
|
549
|
-
path.join(tmpDir, 'astryx.config.mjs'),
|
|
550
|
-
`export default { integrations: ['@acme/widgets', '@acme/extra'] };\n`,
|
|
551
|
-
);
|
|
552
|
-
|
|
553
|
-
const result = await layoutExpand('C{card-callout}', {
|
|
554
|
-
name: 'ReplacementLayout',
|
|
555
|
-
cwd: tmpDir,
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
expect(result.data.code).toContain('Acme replacement block');
|
|
559
|
-
expect(result.data.code).not.toContain('Accidental block');
|
|
560
|
-
expect(result.data.blocksReferenced).toEqual(
|
|
561
|
-
expect.arrayContaining([
|
|
562
|
-
expect.objectContaining({name: 'CardCallout', mode: 'splice'}),
|
|
563
|
-
]),
|
|
564
|
-
);
|
|
565
|
-
}, 30_000);
|
|
566
|
-
|
|
567
|
-
it('resolves chained block aliases consistently in template and layout', async () => {
|
|
520
|
+
it('resolves chained block aliases consistently in template', async () => {
|
|
568
521
|
const [firstTarget, secondTarget] = (await discoverCoreTemplates()).filter(
|
|
569
522
|
candidate => candidate.type === 'block',
|
|
570
523
|
);
|
|
@@ -592,29 +545,12 @@ describe('integration template discovery', () => {
|
|
|
592
545
|
cwd: tmpDir,
|
|
593
546
|
});
|
|
594
547
|
expect(firstTemplate.data.source).toContain('First chain replacement');
|
|
595
|
-
const layoutId = id =>
|
|
596
|
-
id.replace(/([a-z0-9])([A-Z])/gu, '$1-$2').toLowerCase();
|
|
597
|
-
const firstLayout = await layoutExpand(
|
|
598
|
-
`C{${layoutId(firstTarget.dirName)}}`,
|
|
599
|
-
{
|
|
600
|
-
cwd: tmpDir,
|
|
601
|
-
},
|
|
602
|
-
);
|
|
603
|
-
expect(firstLayout.data.code).toContain('First chain replacement');
|
|
604
|
-
expect(firstLayout.data.code).not.toContain('Final chain replacement');
|
|
605
548
|
|
|
606
549
|
const secondTemplate = await template(secondTarget.dirName, {
|
|
607
550
|
show: true,
|
|
608
551
|
cwd: tmpDir,
|
|
609
552
|
});
|
|
610
553
|
expect(secondTemplate.data.source).toContain('Final chain replacement');
|
|
611
|
-
const secondLayout = await layoutExpand(
|
|
612
|
-
`C{${layoutId(secondTarget.dirName)}}`,
|
|
613
|
-
{
|
|
614
|
-
cwd: tmpDir,
|
|
615
|
-
},
|
|
616
|
-
);
|
|
617
|
-
expect(secondLayout.data.code).toContain('Final chain replacement');
|
|
618
554
|
}, 30_000);
|
|
619
555
|
|
|
620
556
|
it('keeps the old discovery behavior when no replacement is declared', async () => {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* the requested one, and routes to a leaf (list/show/skeleton/copy/cdn). The shared
|
|
9
9
|
* discovery/IO + cross-command helpers live in `foundation/discovery/template-adapter.mjs` and are
|
|
10
10
|
* RE-EXPORTED here so external import paths (`api/template/template.mjs`) —
|
|
11
|
-
* used by component,
|
|
11
|
+
* used by component, search, init, discover, Doctor integration, and
|
|
12
12
|
* lib/project — keep resolving unchanged.
|
|
13
13
|
*
|
|
14
14
|
* @position api/template — the template dispatcher + barrel; leaves live under
|
package/api/upgrade/run/run.mjs
CHANGED
|
@@ -114,7 +114,7 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
|
|
|
114
114
|
// Resolve the source dir against the API's cwd (not process.cwd()) so a
|
|
115
115
|
// programmatic caller in another directory scans the right tree. Confine it to
|
|
116
116
|
// cwd: --apply rewrites files in place, so a `..`-escaping or out-of-tree
|
|
117
|
-
// absolute --path must be rejected (parity with template/theme/swizzle
|
|
117
|
+
// absolute --path must be rejected (parity with template/theme/swizzle,
|
|
118
118
|
// and this is the most destructive command). allowAbsolute permits an absolute
|
|
119
119
|
// path that still resolves inside cwd.
|
|
120
120
|
let path_;
|
|
@@ -77,7 +77,7 @@ export const doc = {
|
|
|
77
77
|
name: 'experimental.xle.components',
|
|
78
78
|
type: 'Record<string, XleComponent>',
|
|
79
79
|
description:
|
|
80
|
-
'
|
|
80
|
+
'No effect. Its only reader was the removed `layout` command. The key is still accepted so existing configs keep loading; delete it.',
|
|
81
81
|
},
|
|
82
82
|
],
|
|
83
83
|
},
|
package/authoring/config/type.ts
CHANGED
|
@@ -115,8 +115,8 @@ export interface AstryxConfig {
|
|
|
115
115
|
/** Experimental XLE (layout expression) configuration. */
|
|
116
116
|
xle?: {
|
|
117
117
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
118
|
+
* No effect. Its only reader was the removed `layout` command. Still
|
|
119
|
+
* accepted so existing configs keep loading; delete it.
|
|
120
120
|
*/
|
|
121
121
|
components?: Record<string, XleComponent>;
|
|
122
122
|
};
|
|
@@ -75,7 +75,7 @@ export interface CommandDoc extends AuthoredDocGraphFields {
|
|
|
75
75
|
args?: CommandArgDoc[];
|
|
76
76
|
/** Flags/options. */
|
|
77
77
|
options?: CommandOptionDoc[];
|
|
78
|
-
/** Subcommand names (for command groups like `theme`
|
|
78
|
+
/** Subcommand names (for command groups like `theme`). */
|
|
79
79
|
subcommands?: string[];
|
|
80
80
|
/** Terminal examples. */
|
|
81
81
|
examples?: CommandExampleDoc[];
|
|
@@ -29,17 +29,17 @@ import {program} from './index.mjs';
|
|
|
29
29
|
import {reportsResult, reportsResultVia} from './lib/define-command.mjs';
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* Commands with no action of their own:
|
|
33
|
-
*
|
|
32
|
+
* Commands with no action of their own: a group that prints its subcommand
|
|
33
|
+
* list and does nothing else has no run to report on.
|
|
34
34
|
*
|
|
35
35
|
* Pinned as a SET rather than skipped silently — if a command joins this list,
|
|
36
36
|
* that is a real change to what the CLI does and it should be read, not
|
|
37
|
-
* absorbed.
|
|
38
|
-
* rejects an unknown subcommand — so it goes through the
|
|
39
|
-
* other. Its bare form prints help and never returns from
|
|
40
|
-
* the recorder covers where help is recorded, not here.
|
|
37
|
+
* absorbed. Every group ships an action today: `theme`, for instance, HAS one
|
|
38
|
+
* — the one that rejects an unknown subcommand — so it goes through the
|
|
39
|
+
* converter like any other. Its bare form prints help and never returns from
|
|
40
|
+
* that action, which the recorder covers where help is recorded, not here.
|
|
41
41
|
*/
|
|
42
|
-
const NO_ACTION_OF_THEIR_OWN = [
|
|
42
|
+
const NO_ACTION_OF_THEIR_OWN = [];
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Commands that record for themselves instead of returning a descriptor.
|
|
@@ -179,9 +179,9 @@ describe('DebugEvent result summary', () => {
|
|
|
179
179
|
it(
|
|
180
180
|
'says so explicitly when a command has no result set',
|
|
181
181
|
async () => {
|
|
182
|
-
//
|
|
182
|
+
// Bare `integration` prints its subcommand list: nothing was looked
|
|
183
183
|
// up, and the run says that rather than leaving four ambiguous nulls.
|
|
184
|
-
const {event} = await runWithDebug(['
|
|
184
|
+
const {event} = await runWithDebug(['integration']);
|
|
185
185
|
expect(event.output).toMatchObject({
|
|
186
186
|
resultKind: 'none',
|
|
187
187
|
resultCount: null,
|
|
@@ -377,23 +377,6 @@ const CASES = [
|
|
|
377
377
|
// Needs a packable project; pack itself may exit differently.
|
|
378
378
|
skipFieldChecks: true,
|
|
379
379
|
},
|
|
380
|
-
// ── Layout command: remove these cases when the layout command is deleted ──
|
|
381
|
-
{
|
|
382
|
-
name: 'layout check',
|
|
383
|
-
args: ['layout', 'check', 'Button'],
|
|
384
|
-
skipFieldChecks: true,
|
|
385
|
-
},
|
|
386
|
-
{
|
|
387
|
-
name: 'layout expand',
|
|
388
|
-
args: ['layout', 'expand', 'Button'],
|
|
389
|
-
skipFieldChecks: true,
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
name: 'layout grammar',
|
|
393
|
-
args: ['layout', 'grammar'],
|
|
394
|
-
skipFieldChecks: true,
|
|
395
|
-
},
|
|
396
|
-
// ── End layout cases ──
|
|
397
380
|
{
|
|
398
381
|
name: 'manifest',
|
|
399
382
|
args: ['manifest'],
|
package/clients/cli/index.mjs
CHANGED
|
@@ -103,9 +103,6 @@ export const JSON_SUPPORTED = new Set([
|
|
|
103
103
|
'doctor integration templates',
|
|
104
104
|
'doctor integration components',
|
|
105
105
|
'doctor integration docs',
|
|
106
|
-
'layout expand',
|
|
107
|
-
'layout check',
|
|
108
|
-
'layout grammar',
|
|
109
106
|
]);
|
|
110
107
|
|
|
111
108
|
/**
|
|
@@ -264,7 +261,6 @@ const commands = [
|
|
|
264
261
|
{name: 'gap-report', path: './commands/gap-report.mjs', register: 'registerGapReport'},
|
|
265
262
|
// agent-docs folded into init — functions still importable from agent-docs.mjs
|
|
266
263
|
{name: 'template', path: './commands/template.mjs', register: 'registerTemplate'},
|
|
267
|
-
{name: 'layout', path: './commands/layout.mjs', register: 'registerLayout'},
|
|
268
264
|
{name: 'upgrade', path: './commands/upgrade.mjs', register: 'registerUpgrade'},
|
|
269
265
|
{name: 'theme', path: './commands/build-theme.mjs', register: 'registerTheme'},
|
|
270
266
|
{name: 'integration', path: './commands/integration.mjs', register: 'registerIntegration'},
|
|
@@ -34,7 +34,7 @@ manifest.commands.forEach(walk);
|
|
|
34
34
|
|
|
35
35
|
describe('command exit codes', () => {
|
|
36
36
|
it('every CommandDoc documents its exit codes', () => {
|
|
37
|
-
expect(commandDocs.length).toBeGreaterThan(
|
|
37
|
+
expect(commandDocs.length).toBeGreaterThan(25);
|
|
38
38
|
for (const doc of commandDocs) {
|
|
39
39
|
expect(doc.exitCodes?.length, doc.name).toBeGreaterThan(0);
|
|
40
40
|
}
|
|
@@ -54,13 +54,6 @@ describe('command exit codes', () => {
|
|
|
54
54
|
},
|
|
55
55
|
);
|
|
56
56
|
|
|
57
|
-
it('bare `astryx layout` exits 1 in both modes, as documented', async () => {
|
|
58
|
-
const doc = commandDocs.find((d) => d.name === 'layout');
|
|
59
|
-
expect(doc.exitCodes.find((e) => e.code === 1)?.when).toMatch(/^no subcommand/);
|
|
60
|
-
expect((await runCli(['layout'])).status).toBe(1);
|
|
61
|
-
expect((await runCli(['layout', '--json'])).status).toBe(1);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
57
|
it('`astryx discover` with a blank query exits 1 only when packages are discovered', async () => {
|
|
65
58
|
const doc = commandDocs.find((d) => d.name === 'discover');
|
|
66
59
|
expect(doc.exitCodes.find((e) => e.code === 1)?.when).toMatch(/blank query when packages are discovered/);
|
|
@@ -225,23 +225,6 @@ describe('--json shim: help shown for a failed invocation is an error envelope',
|
|
|
225
225
|
expect(parsed.error).toMatch(/bogus/);
|
|
226
226
|
});
|
|
227
227
|
|
|
228
|
-
it('astryx layout --json (group, no subcommand) emits ERR_MISSING_ARGUMENT, exit 1', async () => {
|
|
229
|
-
const {status, stdout, stderr} = await runCli(['layout', '--json']);
|
|
230
|
-
expect(status).toBe(1);
|
|
231
|
-
expect(stderr).toBe('');
|
|
232
|
-
const parsed = parseJson(stdout);
|
|
233
|
-
expect(parsed).not.toHaveProperty('type');
|
|
234
|
-
expect(parsed.code).toBe('ERR_MISSING_ARGUMENT');
|
|
235
|
-
expect(parsed.suggestions.map((s) => s.name)).toContain('layout expand');
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it('astryx layout (no --json) still prints help to stderr, exit 1', async () => {
|
|
239
|
-
const {status, stdout, stderr} = await runCli(['layout']);
|
|
240
|
-
expect(status).toBe(1);
|
|
241
|
-
expect(stdout).toBe('');
|
|
242
|
-
expect(stderr).toMatch(/Usage: astryx layout/);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
228
|
it('the real binary emits the same envelope for help bogus --json', () => {
|
|
246
229
|
// One program per process, so the root's own outputHelp patch is used here.
|
|
247
230
|
const bin = fileURLToPath(new URL('../bin/astryx.mjs', import.meta.url));
|
|
@@ -257,6 +240,9 @@ describe('--json shim: help shown for a failed invocation is an error envelope',
|
|
|
257
240
|
});
|
|
258
241
|
|
|
259
242
|
it('a group added after install gets the same error envelope', () => {
|
|
243
|
+
// This is the only coverage of the no-subcommand path: every group the CLI
|
|
244
|
+
// ships has an action of its own (see command-result-coverage.test.mjs), so
|
|
245
|
+
// a group without one has to be built here.
|
|
260
246
|
const program = new Command('astryx');
|
|
261
247
|
installJsonShim(program);
|
|
262
248
|
// Added later, so only the prototype-level patch covers its outputHelp.
|
|
@@ -282,11 +268,11 @@ describe('--json shim: help shown for a failed invocation is an error envelope',
|
|
|
282
268
|
expect(parsed.suggestions).toEqual([{name: 'late child', reason: 'available subcommand'}]);
|
|
283
269
|
});
|
|
284
270
|
|
|
285
|
-
it('astryx help
|
|
286
|
-
const {status, stdout} = await runCli(['help', '
|
|
271
|
+
it('astryx help theme --json still emits the help envelope, exit 0', async () => {
|
|
272
|
+
const {status, stdout} = await runCli(['help', 'theme', '--json']);
|
|
287
273
|
expect(status).toBe(0);
|
|
288
274
|
const parsed = parseJson(stdout);
|
|
289
275
|
expect(parsed.type).toBe('help');
|
|
290
|
-
expect(parsed.data.command).toBe('astryx
|
|
276
|
+
expect(parsed.data.command).toBe('astryx theme');
|
|
291
277
|
});
|
|
292
278
|
});
|
|
@@ -100,9 +100,6 @@ export const RESPONSE_TYPES = {
|
|
|
100
100
|
'doctor integration templates': ['integration.template-conflicts'],
|
|
101
101
|
'doctor integration components': ['integration.component-conflicts'],
|
|
102
102
|
'doctor integration docs': ['integration.doc-conflicts'],
|
|
103
|
-
'layout expand': ['layout.expand'],
|
|
104
|
-
'layout check': ['layout.check'],
|
|
105
|
-
'layout grammar': ['layout.grammar'],
|
|
106
103
|
};
|
|
107
104
|
|
|
108
105
|
/**
|
|
@@ -183,11 +180,6 @@ const EXAMPLES = {
|
|
|
183
180
|
'astryx doctor integration docs @acme/widgets --json',
|
|
184
181
|
],
|
|
185
182
|
init: ['astryx init', 'astryx init --all --json'],
|
|
186
|
-
'layout expand': [
|
|
187
|
-
`astryx layout expand 'V[g6] > C{card-callout}*4' ./src/Page.tsx`,
|
|
188
|
-
],
|
|
189
|
-
'layout check': [`astryx layout check 'A[cp6] > L > LC > S[p6]' --json`],
|
|
190
|
-
'layout grammar': ['astryx layout grammar'],
|
|
191
183
|
};
|
|
192
184
|
|
|
193
185
|
/**
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @file Shared template discovery + IO.
|
|
5
5
|
*
|
|
6
6
|
* Owns everything the template leaves (list/show/skeleton/copy) AND other
|
|
7
|
-
* commands (component,
|
|
7
|
+
* commands (component, search, init, discover, Doctor integration)
|
|
8
8
|
* share: template discovery across core/external/integration sources, the
|
|
9
9
|
* template-spec loaders, and the cross-command helpers (stripTemplateAssetRefs,
|
|
10
10
|
* findShowcase, findRelatedBlocks, extractComponents, listTemplates). The
|
|
@@ -191,18 +191,6 @@ const RUNNERS = {
|
|
|
191
191
|
'import ./integration.doc.mjs',
|
|
192
192
|
],
|
|
193
193
|
},
|
|
194
|
-
'clients/cli/commands/layout.mjs': {
|
|
195
|
-
runs: SELF_DOCS,
|
|
196
|
-
sites: [
|
|
197
|
-
'import ../../../api/layout/layoutCheck.doc.mjs',
|
|
198
|
-
'import ../../../api/layout/layoutExpand.doc.mjs',
|
|
199
|
-
'import ../../../api/layout/layoutGrammar.doc.mjs',
|
|
200
|
-
'import ./layout-check.doc.mjs',
|
|
201
|
-
'import ./layout-expand.doc.mjs',
|
|
202
|
-
'import ./layout-grammar.doc.mjs',
|
|
203
|
-
'import ./layout.doc.mjs',
|
|
204
|
-
],
|
|
205
|
-
},
|
|
206
194
|
'clients/cli/commands/search.mjs': {
|
|
207
195
|
runs: SELF_DOCS,
|
|
208
196
|
sites: [
|
|
@@ -318,22 +318,5 @@ export const doc = {
|
|
|
318
318
|
description:
|
|
319
319
|
'The integration identity, structural issues, and Core doc overlaps. Each finding includes `severity` (`info` | `error`) and `relationship` (`replaces` | `extends` | `accidental`).',
|
|
320
320
|
},
|
|
321
|
-
|
|
322
|
-
// layout (XLE/XLO)
|
|
323
|
-
{
|
|
324
|
-
value: 'layout.expand',
|
|
325
|
-
description:
|
|
326
|
-
'The expansion: parsed form, generated TSX code, componentsUsed, states (count of useState hooks scaffolded), todos, blocksReferenced (each {name, mode}), warnings, and written (the output path, or null when nothing was written).',
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
value: 'layout.check',
|
|
330
|
-
description:
|
|
331
|
-
'The validation result: a valid flag, the detected form, errors (each with line/col, message, formatted text, and suggestions), warnings, and the expression re-printed in both canonical surfaces (compact and outline).',
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
value: 'layout.grammar',
|
|
335
|
-
description:
|
|
336
|
-
"The XLE/XLO grammar cheatsheet: a text field with the full reference plus an aliases map (short name → canonical component) generated from this install's registry.",
|
|
337
|
-
},
|
|
338
321
|
],
|
|
339
322
|
};
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Validate an expression and return both canonical surfaces
|
|
6
|
-
*
|
|
5
|
+
* Validate an expression and return both canonical surfaces. Never throws on
|
|
6
|
+
* invalid input; returns the errors.
|
|
7
7
|
*
|
|
8
8
|
* @param {string} expression
|
|
9
9
|
* @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry - serialized or hydrated
|
|
@@ -19,7 +19,7 @@ export function checkExpression(expression: string, registry: import("./xle-ast"
|
|
|
19
19
|
loose?: boolean | undefined;
|
|
20
20
|
}): import("./browser").CheckResult;
|
|
21
21
|
/**
|
|
22
|
-
* Validate + expand to TSX
|
|
22
|
+
* Validate + expand to TSX.
|
|
23
23
|
* Returns either {code, ...} or {errors} (never writes files).
|
|
24
24
|
*
|
|
25
25
|
* @param {string} expression
|
|
@@ -44,8 +44,8 @@ function formatIssue(issue) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* Validate an expression and return both canonical surfaces
|
|
48
|
-
*
|
|
47
|
+
* Validate an expression and return both canonical surfaces. Never throws on
|
|
48
|
+
* invalid input; returns the errors.
|
|
49
49
|
*
|
|
50
50
|
* @param {string} expression
|
|
51
51
|
* @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry - serialized or hydrated
|
|
@@ -85,7 +85,7 @@ export function checkExpression(expression, registry, opts = {}) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* Validate + expand to TSX
|
|
88
|
+
* Validate + expand to TSX.
|
|
89
89
|
* Returns either {code, ...} or {errors} (never writes files).
|
|
90
90
|
*
|
|
91
91
|
* @param {string} expression
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @input validated doc (nodes carry .bound) + registry
|
|
15
15
|
* @output expand() → {code, componentsUsed, states, todos}
|
|
16
|
-
* @position lib/xle — last stage;
|
|
16
|
+
* @position lib/xle — last stage; the browser barrel orchestrates
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import {PAYLOAD_PROPS} from './validate.mjs';
|
|
@@ -751,7 +751,7 @@ export function expand(doc, registry, options = {}) {
|
|
|
751
751
|
: [];
|
|
752
752
|
|
|
753
753
|
const code = [
|
|
754
|
-
`// Generated by
|
|
754
|
+
`// Generated by the Astryx XLE expander — this file is the artifact; edit freely.`,
|
|
755
755
|
...importLines,
|
|
756
756
|
...blockSection,
|
|
757
757
|
'',
|
package/foundation/xle/parse.mjs
CHANGED
|
@@ -302,7 +302,7 @@ function parseAttrToken(token, line) {
|
|
|
302
302
|
* Guard against unbounded recursion in the compact parser. A layout tree this
|
|
303
303
|
* deep is never hand-authored; without the cap the recursive descent blows the
|
|
304
304
|
* JS call stack and surfaces a raw RangeError (→ ERR_UNKNOWN, no line/col)
|
|
305
|
-
* instead of a located
|
|
305
|
+
* instead of a located parse error. The counter is module-level so it
|
|
306
306
|
* spans group / attribute sub-streams; each parse entry point resets it.
|
|
307
307
|
*/
|
|
308
308
|
const MAX_COMPACT_DEPTH = 512;
|
package/foundation/xle/print.mjs
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file XLE canonical printers — AST → compact (XLE) or outline (XLO) text.
|
|
5
5
|
*
|
|
6
|
-
* Used by `
|
|
7
|
-
*
|
|
6
|
+
* Used by `checkExpression` so either party (agent or human) can request the
|
|
7
|
+
* other surface, and by round-trip conformance tests.
|
|
8
8
|
* Printing is best-effort canonical: spelling variants the lexer
|
|
9
9
|
* normalized are emitted in canonical form.
|
|
10
10
|
*
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
* @input block TSX source (splice) or a name+importPath (import)
|
|
20
20
|
* @output prepareSpliceModule / parseImportStatements + import-merge helpers
|
|
21
|
-
* @position lib/xle — used by expand.mjs; sources gathered
|
|
21
|
+
* @position lib/xle — used by expand.mjs; sources gathered by the caller
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
const IMPORT_RE =
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/cli",
|
|
3
|
-
"version": "0.6.4-canary.
|
|
3
|
+
"version": "0.6.4-canary.9cc70a9",
|
|
4
4
|
"displayName": "CLI",
|
|
5
5
|
"description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -101,10 +101,10 @@
|
|
|
101
101
|
"zod": "^4.4.3"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
|
-
"@astryxdesign/charts": "0.6.4-canary.
|
|
105
|
-
"@astryxdesign/core": "0.6.4-canary.
|
|
106
|
-
"@astryxdesign/lab": "0.6.4-canary.
|
|
107
|
-
"@astryxdesign/theme-neutral": "0.6.4-canary.
|
|
104
|
+
"@astryxdesign/charts": "0.6.4-canary.9cc70a9",
|
|
105
|
+
"@astryxdesign/core": "0.6.4-canary.9cc70a9",
|
|
106
|
+
"@astryxdesign/lab": "0.6.4-canary.9cc70a9",
|
|
107
|
+
"@astryxdesign/theme-neutral": "0.6.4-canary.9cc70a9"
|
|
108
108
|
},
|
|
109
109
|
"peerDependenciesMeta": {
|
|
110
110
|
"@astryxdesign/charts": {
|
|
@@ -121,10 +121,10 @@
|
|
|
121
121
|
}
|
|
122
122
|
},
|
|
123
123
|
"devDependencies": {
|
|
124
|
-
"@astryxdesign/charts": "0.6.4-canary.
|
|
125
|
-
"@astryxdesign/core": "0.6.4-canary.
|
|
126
|
-
"@astryxdesign/lab": "0.6.4-canary.
|
|
127
|
-
"@astryxdesign/theme-neutral": "0.6.4-canary.
|
|
124
|
+
"@astryxdesign/charts": "0.6.4-canary.9cc70a9",
|
|
125
|
+
"@astryxdesign/core": "0.6.4-canary.9cc70a9",
|
|
126
|
+
"@astryxdesign/lab": "0.6.4-canary.9cc70a9",
|
|
127
|
+
"@astryxdesign/theme-neutral": "0.6.4-canary.9cc70a9",
|
|
128
128
|
"@heroicons/react": "^2.2.0",
|
|
129
129
|
"@stylexjs/stylex": "^0.19.0",
|
|
130
130
|
"@types/babel__core": "^7.20.5",
|