@astryxdesign/cli 0.7.2-canary.c9f2659 → 0.7.2-canary.cbb7fa3

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.
Files changed (72) hide show
  1. package/api/component/_adapter.d.mts +41 -1
  2. package/api/component/_adapter.mjs +93 -7
  3. package/api/component/component.mjs +22 -5
  4. package/api/component/component.test.mjs +420 -167
  5. package/api/component/integration-export-name.test.mjs +644 -0
  6. package/api/component/list/list.mjs +42 -4
  7. package/api/gap-report/gap-report.mjs +67 -4
  8. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  9. package/api/integration/add-contribution.mjs +7 -3
  10. package/api/integration/pack-check.mjs +61 -107
  11. package/api/integration/pack-check.test.mjs +359 -0
  12. package/api/search/search.d.mts +9 -0
  13. package/api/search/search.mjs +108 -16
  14. package/api/search/search.test.mjs +36 -0
  15. package/api/swizzle/copy/copy.mjs +28 -14
  16. package/api/template/template.test.mjs +120 -3
  17. package/api/theme/build/build.family.test.mjs +16 -0
  18. package/api/theme/build/build.mjs +77 -18
  19. package/api/theme/themeBuild.doc.mjs +3 -3
  20. package/assets/codemods/transforms/next/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
  21. package/assets/codemods/transforms/next/index.mjs +11 -1
  22. package/assets/codemods/transforms/next/migrate-list-edge-compensation-to-edge.mjs +198 -0
  23. package/assets/docs/tree/add-a-component.doc.mjs +10 -0
  24. package/assets/docs/tree/checks.doc.mjs +1 -1
  25. package/assets/docs/tree/component-family.doc.mjs +5 -1
  26. package/assets/docs/tree/component-imports.doc.mjs +8 -0
  27. package/assets/docs/tree/single-component.doc.mjs +1 -1
  28. package/assets/docs/tree/troubleshooting.doc.mjs +9 -1
  29. package/assets/docs/tree/versioning.doc.mjs +1 -0
  30. package/assets/docs/working-with-ai.doc.mjs +43 -4
  31. package/assets/templates/blocks/components/Drawer/DrawerForm.doc.mjs +24 -0
  32. package/assets/templates/blocks/components/Drawer/DrawerForm.tsx +62 -0
  33. package/assets/templates/blocks/components/Drawer/DrawerScrim.doc.mjs +22 -0
  34. package/assets/templates/blocks/components/Drawer/DrawerScrim.tsx +68 -0
  35. package/assets/templates/blocks/components/Drawer/DrawerShowcase.doc.mjs +22 -0
  36. package/assets/templates/blocks/components/Drawer/DrawerShowcase.tsx +41 -0
  37. package/assets/templates/blocks/components/Drawer/DrawerStart.doc.mjs +21 -0
  38. package/assets/templates/blocks/components/Drawer/DrawerStart.tsx +41 -0
  39. package/assets/templates/blocks/components/Drawer/DrawerWidths.doc.mjs +22 -0
  40. package/assets/templates/blocks/components/Drawer/DrawerWidths.tsx +54 -0
  41. package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderShowcase.doc.mjs +15 -0
  42. package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderShowcase.tsx +73 -0
  43. package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderSubtitleEndContent.doc.mjs +22 -0
  44. package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderSubtitleEndContent.tsx +49 -0
  45. package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderWithCloseButton.doc.mjs +21 -0
  46. package/assets/templates/blocks/components/DrawerHeader/DrawerHeaderWithCloseButton.tsx +42 -0
  47. package/assets/templates/pages/detail-page/page.tsx +3 -3
  48. package/assets/templates/pages/table-inbox/page.tsx +10 -8
  49. package/authoring/doctypes/base/type.ts +6 -0
  50. package/authoring/doctypes/component/component.doc.mjs +4 -4
  51. package/authoring/doctypes/component/type.ts +6 -3
  52. package/clients/cli/commands/build-theme.path-safety.test.mjs +84 -0
  53. package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
  54. package/clients/cli/commands/theme-build.doc.mjs +2 -2
  55. package/clients/cli/lib/component-format.mjs +5 -1
  56. package/foundation/discovery/component-discovery.d.mts +172 -10
  57. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  58. package/foundation/discovery/component-discovery.mjs +863 -55
  59. package/foundation/discovery/component-discovery.test.mjs +96 -0
  60. package/foundation/discovery/component-replacement.mjs +18 -0
  61. package/foundation/discovery/component-replacement.test.mjs +40 -0
  62. package/foundation/discovery/module-exports.d.mts +27 -0
  63. package/foundation/discovery/module-exports.mjs +356 -31
  64. package/foundation/discovery/module-exports.test.mjs +172 -0
  65. package/foundation/discovery/template-adapter.mjs +74 -5
  66. package/foundation/doc-compiler/doc-loads.test.mjs +5 -1
  67. package/foundation/doc-compiler/inputs.mjs +23 -0
  68. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  69. package/foundation/integrations/contribution-inventory.mjs +6 -1
  70. package/foundation/xle/registry.mjs +4 -0
  71. package/foundation/xle/registry.test.mjs +28 -0
  72. package/package.json +10 -10
@@ -0,0 +1,172 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Static reads of a module's exports, without running it: the file that
5
+ * declares an export, and an exported object literal as plain data.
6
+ */
7
+
8
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest';
9
+ import * as fs from 'node:fs';
10
+ import * as os from 'node:os';
11
+ import * as path from 'node:path';
12
+ import {moduleExportSource, staticExportObject} from './module-exports.mjs';
13
+
14
+ /** @type {string} */
15
+ let dir;
16
+
17
+ beforeEach(() => {
18
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-export-field-'));
19
+ });
20
+
21
+ afterEach(() => {
22
+ fs.rmSync(dir, {recursive: true, force: true});
23
+ });
24
+
25
+ /**
26
+ * @param {string} file
27
+ * @param {string} source
28
+ * @returns {string}
29
+ */
30
+ function write(file, source) {
31
+ const filePath = path.join(dir, file);
32
+ fs.writeFileSync(filePath, source);
33
+ return filePath;
34
+ }
35
+
36
+ const DOC_EXPORTS = ['default', 'docs'];
37
+
38
+ describe('staticExportObject', () => {
39
+ it('reads a default-exported object literal as plain data', () => {
40
+ const file = write(
41
+ 'A.doc.mjs',
42
+ "export default {type: 'component', name: 'AcmeCarousel', order: 2, hidden: false, extra: null};\n",
43
+ );
44
+ expect(staticExportObject(file, DOC_EXPORTS)).toEqual({
45
+ type: 'component',
46
+ name: 'AcmeCarousel',
47
+ order: 2,
48
+ hidden: false,
49
+ extra: null,
50
+ });
51
+ });
52
+
53
+ it('reads a named export, an export list, and the first export it looks for', () => {
54
+ const named = write(
55
+ 'B.doc.mjs',
56
+ "/** @type {object} */\nexport const docs = {\n name: 'AcmeCarousel',\n};\n",
57
+ );
58
+ const both = write(
59
+ 'C.doc.mjs',
60
+ "export const docs = {name: 'Legacy'};\nexport default {name: 'Stamped'};\n",
61
+ );
62
+ const list = write(
63
+ 'E.doc.mjs',
64
+ "const local = {name: 'AcmeCarousel'};\nexport {local as docs};\n",
65
+ );
66
+ expect(staticExportObject(named, DOC_EXPORTS)?.name).toBe('AcmeCarousel');
67
+ expect(staticExportObject(both, DOC_EXPORTS)?.name).toBe('Stamped');
68
+ expect(staticExportObject(list, DOC_EXPORTS)?.name).toBe('AcmeCarousel');
69
+ });
70
+
71
+ it('follows top-level bindings through TypeScript wrappers, at any depth', () => {
72
+ const file = write(
73
+ 'D.doc.ts',
74
+ [
75
+ "const slide = {name: 'AcmeSlide', description: 'One slide.'} as const;",
76
+ "const doc = {name: 'AcmeCarousel', components: [slide, {name: 'AcmeDots', description: 'Dots.'}]} satisfies {name: string};",
77
+ 'export default doc;',
78
+ '',
79
+ ].join('\n'),
80
+ );
81
+ expect(staticExportObject(file, DOC_EXPORTS)).toEqual({
82
+ name: 'AcmeCarousel',
83
+ components: [
84
+ {name: 'AcmeSlide', description: 'One slide.'},
85
+ {name: 'AcmeDots', description: 'Dots.'},
86
+ ],
87
+ });
88
+ });
89
+
90
+ it('leaves out what it cannot read without running the module', () => {
91
+ const file = write(
92
+ 'F.doc.mjs',
93
+ [
94
+ "const prefix = 'Acme';",
95
+ 'const shared = {group: "Media"};',
96
+ 'export default {',
97
+ ' // A computed string, a call and a spread: none is read.',
98
+ ' name: `${prefix}Carousel`,',
99
+ ' usage: makeUsage(),',
100
+ " group: 'Overridden',",
101
+ ' ...shared,',
102
+ " category: 'Media',",
103
+ " components: [...more, {name: 'AcmeSlide'}],",
104
+ '};',
105
+ '',
106
+ ].join('\n'),
107
+ );
108
+ expect(staticExportObject(file, DOC_EXPORTS)).toEqual({
109
+ category: 'Media',
110
+ components: [{name: 'AcmeSlide'}],
111
+ });
112
+ });
113
+
114
+ it('answers null when there is no exported object', () => {
115
+ const files = [
116
+ write(
117
+ 'G.doc.mjs',
118
+ "export const docs = {name: 'Legacy'};\nexport default makeDoc();\n",
119
+ ),
120
+ write('H.doc.mjs', 'export default {name: '),
121
+ write('I.doc.mjs', "export const other = {name: 'AcmeCarousel'};\n"),
122
+ write('J.doc.mjs', "export default ['AcmeCarousel'];\n"),
123
+ ];
124
+ for (const file of files) {
125
+ expect(staticExportObject(file, DOC_EXPORTS)).toBeNull();
126
+ }
127
+ });
128
+ });
129
+
130
+ describe('moduleExportSource', () => {
131
+ it('names the file that declares an export, following local re-exports', () => {
132
+ const impl = write(
133
+ 'impl.tsx',
134
+ 'export function AcmeSlide() { return null; }\n',
135
+ );
136
+ const barrel = write(
137
+ 'index.ts',
138
+ "export {AcmeSlide} from './impl';\nexport * from './dots';\nexport function AcmeCarousel() { return null; }\n",
139
+ );
140
+ const dots = write('dots.tsx', 'export const AcmeDots = () => null;\n');
141
+ expect(moduleExportSource(barrel, 'AcmeSlide')).toBe(impl);
142
+ expect(moduleExportSource(barrel, 'AcmeDots')).toBe(dots);
143
+ expect(moduleExportSource(barrel, 'AcmeCarousel')).toBe(barrel);
144
+ expect(moduleExportSource(barrel, 'AcmeMissing')).toBeNull();
145
+ });
146
+
147
+ it('does not follow a re-export written in a comment', () => {
148
+ write('legacy.tsx', 'export function AcmeTab() { return null; }\n');
149
+ const barrel = write(
150
+ 'tabs.ts',
151
+ "// export * from './legacy';\nexport function AcmeTabs() { return null; }\n",
152
+ );
153
+ expect(moduleExportSource(barrel, 'AcmeTab')).toBeNull();
154
+ });
155
+
156
+ it('does not count a type-only export', () => {
157
+ const file = write('types.ts', 'export type AcmeShape = {id: string};\n');
158
+ expect(moduleExportSource(file, 'AcmeShape')).toBeNull();
159
+ });
160
+
161
+ it('sees a file npm replaced with one of the same size and mtime', () => {
162
+ // npm stamps every installed file with one mtime and writes new files.
163
+ const npmTime = new Date('1985-10-26T08:15:00Z');
164
+ const file = write('Panel.tsx', 'export function AcmePanel() {}\n');
165
+ fs.utimesSync(file, npmTime, npmTime);
166
+ expect(moduleExportSource(file, 'AcmePanel')).toBe(file);
167
+ const next = write('Panel.next.tsx', 'export function AcmePanol() {}\n');
168
+ fs.utimesSync(next, npmTime, npmTime);
169
+ fs.renameSync(next, file);
170
+ expect(moduleExportSource(file, 'AcmePanel')).toBeNull();
171
+ });
172
+ });
@@ -15,7 +15,8 @@
15
15
  * needs it: `Project` assembles templates from it. While this sat in api/, that
16
16
  * made a cycle across the layer boundary — Project reached up for discovery and
17
17
  * this module imported Project back. Nothing here depends on api/; every import
18
- * is node:*, jiti, foundation/*, or authoring/*.
18
+ * is node:*, jiti, foundation/*, or authoring/*, plus a lazily required
19
+ * @babel/parser for extractComponents' local-declaration scan.
19
20
  *
20
21
  * @position packages/cli/foundation/discovery — shared template discovery/IO;
21
22
  * consumed by Project and by the api/template leaves.
@@ -512,6 +513,19 @@ function expressionUse(source, open, close) {
512
513
  return null;
513
514
  }
514
515
 
516
+ /** @type {typeof import('@babel/parser') | undefined} */
517
+ let babelParser;
518
+
519
+ /**
520
+ * The template source parser, loaded on first use so listing templates
521
+ * never pays for it.
522
+ * @returns {typeof import('@babel/parser')}
523
+ */
524
+ function templateSourceParser() {
525
+ babelParser ??= require('@babel/parser');
526
+ return /** @type {typeof import('@babel/parser')} */ (babelParser);
527
+ }
528
+
515
529
  /**
516
530
  * The [start, end) range of every comment in `source`, or none when it does
517
531
  * not parse as TSX.
@@ -520,8 +534,7 @@ function expressionUse(source, open, close) {
520
534
  */
521
535
  function commentRanges(source) {
522
536
  try {
523
- const {parse} = require('@babel/parser');
524
- const {comments} = parse(source, {
537
+ const {comments} = templateSourceParser().parse(source, {
525
538
  sourceType: 'module',
526
539
  plugins: ['jsx', 'typescript'],
527
540
  });
@@ -1267,7 +1280,8 @@ export async function discoverIntegrationTemplatesForOne(integration) {
1267
1280
  template: id,
1268
1281
  message: `Template "${id}" is missing a "type" of "page" or "block". Stamp the default export with type: 'page' or type: 'block'.`,
1269
1282
  });
1270
- const declared = doc?.replaces ?? (await declaredReplacement(docPath, id));
1283
+ const declared =
1284
+ doc?.replaces ?? (await declaredReplacement(docPath, id));
1271
1285
  if (declared != null) {
1272
1286
  errors.push({
1273
1287
  code: 'invalid_template_replacement',
@@ -1423,6 +1437,51 @@ const UBIQUITOUS = new Set([
1423
1437
  'Icon',
1424
1438
  ]);
1425
1439
 
1440
+ /**
1441
+ * Names bound by top-level `function`, `class`, `const`, `let` or `var`
1442
+ * declarations (exported or not). Returns an empty set when the source does
1443
+ * not parse, so a parse failure never drops a real component.
1444
+ *
1445
+ * @param {string} src
1446
+ * @returns {Set<string>}
1447
+ */
1448
+ function topLevelBindingNames(src) {
1449
+ /** @type {Set<string>} */
1450
+ const names = new Set();
1451
+ let program;
1452
+ try {
1453
+ program = templateSourceParser().parse(src, {
1454
+ sourceType: 'module',
1455
+ plugins: ['jsx', 'typescript'],
1456
+ errorRecovery: true,
1457
+ }).program;
1458
+ } catch {
1459
+ return names;
1460
+ }
1461
+ for (const statement of program.body) {
1462
+ const node =
1463
+ statement.type === 'ExportNamedDeclaration' ||
1464
+ statement.type === 'ExportDefaultDeclaration'
1465
+ ? statement.declaration
1466
+ : statement;
1467
+ if (node == null) continue;
1468
+ if (
1469
+ (node.type === 'FunctionDeclaration' ||
1470
+ node.type === 'ClassDeclaration') &&
1471
+ node.id
1472
+ ) {
1473
+ names.add(node.id.name);
1474
+ } else if (node.type === 'VariableDeclaration') {
1475
+ for (const declarator of node.declarations) {
1476
+ if (declarator.id.type === 'Identifier') {
1477
+ names.add(declarator.id.name);
1478
+ }
1479
+ }
1480
+ }
1481
+ }
1482
+ return names;
1483
+ }
1484
+
1426
1485
  /**
1427
1486
  * @param {string} pagePath
1428
1487
  * @returns {string[]}
@@ -1449,14 +1508,24 @@ export function extractComponents(pagePath) {
1449
1508
  while ((m = tagRegex.exec(src)) !== null) {
1450
1509
  matches.push(m[2]);
1451
1510
  }
1511
+
1512
+ // Exclude names bound by a top-level declaration in the same file: those are
1513
+ // page-local helpers (e.g. `function TimelineSection()`), not components a
1514
+ // builder can import. Read real bindings from the syntax tree so comments,
1515
+ // strings and type annotations cannot add or hide a name.
1516
+ const localDeclNames = topLevelBindingNames(src);
1517
+
1452
1518
  return [
1453
1519
  ...new Set(
1454
1520
  matches
1521
+ .filter(n => !localDeclNames.has(n))
1455
1522
  .filter(n => !['Theme', 'ThemeProvider'].includes(n))
1456
1523
  .filter(n => !UBIQUITOUS.has(n))
1457
1524
  .map(n =>
1458
1525
  n.replace(
1459
- /(Item|Section|Header|Content|Footer|Panel|Heading|CollapseButton|Column|Sortable|Selection|Group|Source)$/,
1526
+ // Strip only when a stem remains, so a bare `<Section>` keeps its
1527
+ // own name instead of emptying out.
1528
+ /(?<=.)(Item|Section|Header|Content|Footer|Panel|Heading|CollapseButton|Column|Sortable|Selection|Group|Source)$/,
1460
1529
  '',
1461
1530
  ),
1462
1531
  )
@@ -246,12 +246,16 @@ const RUNNERS = {
246
246
  runs: 'astryx.config, through the config parser',
247
247
  sites: ['loadModuleWithParser(..., parseConfig)'],
248
248
  },
249
+ 'foundation/discovery/component-discovery.mjs': {
250
+ runs: '@babel/parser, on first use, to read the members a family doc lists in its components without running the doc',
251
+ sites: ['require(@babel/parser)'],
252
+ },
249
253
  'foundation/discovery/docs-discovery.mjs': {
250
254
  runs: 'a contributed topic, for its catalog fields: name, title, description, category, and relationships',
251
255
  sites: ['importDocModule'],
252
256
  },
253
257
  'foundation/discovery/template-adapter.mjs': {
254
- runs: '@babel/parser, to find the fixture references in template source; and a template doc that does not validate, to read the replacement it declares',
258
+ runs: '@babel/parser, to find the fixture references and page-local bindings in template source; and a template doc that does not validate, to read the replacement it declares',
255
259
  sites: ['importDocModule', 'require(@babel/parser)'],
256
260
  },
257
261
  'foundation/discovery/theme-discovery.mjs': {
@@ -81,8 +81,31 @@ const NON_DESCRIPTOR_DIRS = new Set([
81
81
  export async function collectDocInputs(project) {
82
82
  const list = new InputList();
83
83
 
84
+ // A component documented as a member of its family's doc (HStack and VStack
85
+ // in Stack's doc) is read through the family's own entry: one descriptor,
86
+ // one reader. Own docs go first so the family keeps its name.
87
+ /** @type {Array<{name: string, package: string, docPath: string}>} */
88
+ const ownDocs = [];
89
+ /** @type {Array<{name: string, package: string, docPath: string}>} */
90
+ const familyDocs = [];
84
91
  for (const record of await project.components()) {
85
92
  if (record.docPath == null) continue;
93
+ const stem = path
94
+ .basename(record.docPath)
95
+ .replace(/\.doc\.[cm]?[jt]s$/u, '')
96
+ .replace(/^XDS/u, '');
97
+ const entry = {
98
+ name: record.name,
99
+ package: record.package,
100
+ docPath: record.docPath,
101
+ };
102
+ (stem === record.name ? ownDocs : familyDocs).push(entry);
103
+ }
104
+ for (const record of ownDocs) {
105
+ list.add('components', record.name, record.package, record.docPath);
106
+ }
107
+ for (const record of familyDocs) {
108
+ if (list.claims(record.docPath)) continue;
86
109
  list.add('components', record.name, record.package, record.docPath);
87
110
  }
88
111
 
@@ -91,7 +91,6 @@ describe('collectDocInputs over what this repo ships', () => {
91
91
  'Chat',
92
92
  'ChatComposerTokenElement',
93
93
  'ContextMenuItem',
94
- 'Heading',
95
94
  'Indicator',
96
95
  'Layer',
97
96
  'NavMenu',
@@ -248,11 +248,16 @@ export async function collectIdentities(loaded) {
248
248
  if (loaded.components && fs.existsSync(loaded.components)) {
249
249
  try {
250
250
  const records = discoverIntegrationComponents(loaded) ?? [];
251
+ // A family doc backs several records: load it, and report it, once.
252
+ const loads = new Map();
251
253
  for (const record of records) {
254
+ const first = !loads.has(record.docPath);
255
+ if (first) loads.set(record.docPath, loadComponentDoc(record.docPath));
252
256
  try {
253
- await loadComponentDoc(record.docPath);
257
+ await loads.get(record.docPath);
254
258
  identities.components.push(record.name);
255
259
  } catch (err) {
260
+ if (!first) continue;
256
261
  errors.push({
257
262
  kind: 'components',
258
263
  message: `${path.relative(loaded.components, record.docPath)}: ${
@@ -20,6 +20,7 @@ import path from 'node:path';
20
20
  import {findCoreDir} from '../fs/paths.mjs';
21
21
  import {
22
22
  discoverComponents,
23
+ familyMember,
23
24
  findComponentReadme,
24
25
  resolveImportPath,
25
26
  } from '../discovery/component-discovery.mjs';
@@ -126,6 +127,9 @@ export async function buildRegistry({cwd = process.cwd()} = {}) {
126
127
  } catch {
127
128
  continue; // a malformed doc must not take down the whole language
128
129
  }
130
+ // A member documented in its family's doc (VStack in Stack's doc) is
131
+ // registered by the family's own folder, with every other member.
132
+ if (familyMember(docs, dirName)) continue;
129
133
  const importPath = resolveImportPath(coreDir, dirName);
130
134
 
131
135
  const register = (/** @type {string} */ rawName, /** @type {import('./xle-ast').DocProp[]} */ props) => {
@@ -0,0 +1,28 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file The layout-language registry over the real @astryxdesign/core tree:
5
+ * the import path it emits for each component.
6
+ */
7
+
8
+ import {describe, it, expect} from 'vitest';
9
+ import * as path from 'node:path';
10
+ import {fileURLToPath} from 'node:url';
11
+ import {buildRegistry} from './registry.mjs';
12
+
13
+ const REPO = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
14
+
15
+ describe('buildRegistry import paths', () => {
16
+ it('keeps the Stack family on the paths it registers from Stack\'s folder', async () => {
17
+ // HStack and VStack are listed components whose docs live in Stack's doc.
18
+ // Listing them must not let their folders re-register the family under
19
+ // their own paths: a member's folder registers nothing, Stack's does.
20
+ const {components} = await buildRegistry({cwd: REPO});
21
+ const importOf = (/** @type {string} */ name) => components.get(name)?.importPath;
22
+ for (const name of ['Stack', 'StackItem', 'HStack', 'VStack']) {
23
+ expect(importOf(name), name).toBe('@astryxdesign/core/Stack');
24
+ }
25
+ expect(importOf('Heading')).toBe('@astryxdesign/core/Heading');
26
+ expect(importOf('Text')).toBe('@astryxdesign/core/Text');
27
+ }, 120_000);
28
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/cli",
3
- "version": "0.7.2-canary.c9f2659",
3
+ "version": "0.7.2-canary.cbb7fa3",
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",
@@ -96,15 +96,15 @@
96
96
  "jscodeshift": "^17.3.0",
97
97
  "node-diff3": "3.2.1",
98
98
  "postcss": "^8.5.23",
99
- "postcss-selector-parser": "^7.1.5",
99
+ "postcss-selector-parser": "^7.1.6",
100
100
  "recast": "0.23.21",
101
101
  "zod": "^4.4.3"
102
102
  },
103
103
  "peerDependencies": {
104
- "@astryxdesign/charts": "0.7.2-canary.c9f2659",
105
- "@astryxdesign/core": "0.7.2-canary.c9f2659",
106
- "@astryxdesign/lab": "0.7.2-canary.c9f2659",
107
- "@astryxdesign/theme-neutral": "0.7.2-canary.c9f2659"
104
+ "@astryxdesign/charts": "0.7.2-canary.cbb7fa3",
105
+ "@astryxdesign/core": "0.7.2-canary.cbb7fa3",
106
+ "@astryxdesign/lab": "0.7.2-canary.cbb7fa3",
107
+ "@astryxdesign/theme-neutral": "0.7.2-canary.cbb7fa3"
108
108
  },
109
109
  "peerDependenciesMeta": {
110
110
  "@astryxdesign/charts": {
@@ -121,10 +121,10 @@
121
121
  }
122
122
  },
123
123
  "devDependencies": {
124
- "@astryxdesign/charts": "0.7.2-canary.c9f2659",
125
- "@astryxdesign/core": "0.7.2-canary.c9f2659",
126
- "@astryxdesign/lab": "0.7.2-canary.c9f2659",
127
- "@astryxdesign/theme-neutral": "0.7.2-canary.c9f2659",
124
+ "@astryxdesign/charts": "0.7.2-canary.cbb7fa3",
125
+ "@astryxdesign/core": "0.7.2-canary.cbb7fa3",
126
+ "@astryxdesign/lab": "0.7.2-canary.cbb7fa3",
127
+ "@astryxdesign/theme-neutral": "0.7.2-canary.cbb7fa3",
128
128
  "@heroicons/react": "^2.2.0",
129
129
  "@stylexjs/stylex": "^0.19.0",
130
130
  "@types/babel__core": "^7.20.5",