@astryxdesign/cli 0.1.1 → 0.1.2-canary.043f3fd

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 (185) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/docs/theme.doc.mjs +2 -2
  3. package/docs/working-with-ai.doc.mjs +6 -6
  4. package/package.json +31 -8
  5. package/src/api/component.mjs +253 -12
  6. package/src/api/discover.mjs +87 -28
  7. package/src/api/doctor.mjs +7 -22
  8. package/src/api/index.mjs +1 -0
  9. package/src/api/layout.mjs +302 -0
  10. package/src/api/layout.test.mjs +241 -0
  11. package/src/api/template-integration.test.mjs +225 -0
  12. package/src/api/template.mjs +421 -122
  13. package/src/api/template.test.mjs +2 -0
  14. package/src/api/theme-add.mjs +182 -0
  15. package/src/api/validate-integration.mjs +370 -0
  16. package/src/api/validate-integration.test.mjs +222 -0
  17. package/src/codemod.mjs +93 -0
  18. package/src/codemod.test.mjs +134 -0
  19. package/src/codemods/__tests__/registry.test.mjs +2 -0
  20. package/src/codemods/__tests__/runner.test.mjs +103 -0
  21. package/src/codemods/integration-discovery.mjs +168 -0
  22. package/src/codemods/integration-discovery.test.mjs +234 -0
  23. package/src/codemods/integration-runner.mjs +109 -0
  24. package/src/codemods/registry.mjs +2 -0
  25. package/src/codemods/run-codemod.mjs +207 -0
  26. package/src/codemods/runner.mjs +73 -96
  27. package/src/codemods/transforms/v0.0.15/index.mjs +0 -13
  28. package/src/codemods/transforms/v0.1.0/__tests__/v0.1.0-ordering.test.mjs +81 -0
  29. package/src/codemods/transforms/{v0.0.15 → v0.1.0}/drop-xds-prefix-imports.mjs +15 -4
  30. package/src/codemods/transforms/v0.1.0/index.mjs +15 -6
  31. package/src/codemods/transforms/v0.1.2/__tests__/rename-text-color-active-to-accent.test.mjs +120 -0
  32. package/src/codemods/transforms/v0.1.2/index.mjs +19 -0
  33. package/src/codemods/transforms/v0.1.2/rename-text-color-active-to-accent.mjs +136 -0
  34. package/src/codemods/transforms/v0.1.3/__tests__/migrate-layout-components-to-experimental.test.mjs +360 -0
  35. package/src/codemods/transforms/v0.1.3/index.mjs +19 -0
  36. package/src/codemods/transforms/v0.1.3/migrate-layout-components-to-experimental.mjs +260 -0
  37. package/src/commands/build-theme.import-path.test.mjs +22 -2
  38. package/src/commands/build-theme.mjs +185 -16
  39. package/src/commands/component/index.mjs +44 -10
  40. package/src/commands/component-ownership.test.mjs +227 -0
  41. package/src/commands/discover.mjs +5 -16
  42. package/src/commands/doctor.test.mjs +3 -3
  43. package/src/commands/init.mjs +34 -8
  44. package/src/commands/init.next-steps.test.mjs +46 -0
  45. package/src/commands/json-contract.test.mjs +0 -32
  46. package/src/commands/layout.mjs +139 -0
  47. package/src/commands/swizzle.mjs +241 -224
  48. package/src/commands/swizzle.path-safety.test.mjs +3 -3
  49. package/src/commands/swizzle.routing.test.mjs +279 -0
  50. package/src/commands/template.mjs +33 -37
  51. package/src/commands/upgrade.config-ordering.test.mjs +273 -0
  52. package/src/commands/upgrade.integration-policy.test.mjs +204 -0
  53. package/src/commands/upgrade.mjs +349 -239
  54. package/src/commands/validate-integration.mjs +110 -0
  55. package/src/commands/validate-integration.test.mjs +124 -0
  56. package/src/config.mjs +18 -0
  57. package/src/config.test.mjs +100 -0
  58. package/src/index.mjs +13 -3
  59. package/src/integration.mjs +19 -0
  60. package/src/lib/component-discovery.mjs +177 -0
  61. package/src/lib/config-cache.mjs +91 -0
  62. package/src/lib/config-cache.test.mjs +83 -0
  63. package/src/lib/config-schema.mjs +105 -0
  64. package/src/lib/error-codes.mjs +18 -12
  65. package/src/lib/integration-warnings.mjs +62 -0
  66. package/src/lib/integration-warnings.test.mjs +102 -0
  67. package/src/lib/integrations.mjs +132 -0
  68. package/src/lib/integrations.test.mjs +135 -0
  69. package/src/lib/levenshtein.mjs +29 -0
  70. package/src/lib/manifest.mjs +15 -2
  71. package/src/lib/module-loader.mjs +80 -0
  72. package/src/lib/module-loader.test.mjs +106 -0
  73. package/src/lib/package-scanner.mjs +31 -7
  74. package/src/lib/project.mjs +502 -0
  75. package/src/lib/project.test.mjs +308 -0
  76. package/src/lib/string-utils.mjs +5 -14
  77. package/src/lib/xle/browser.d.ts +100 -0
  78. package/src/lib/xle/browser.mjs +120 -0
  79. package/src/lib/xle/expand.mjs +622 -0
  80. package/src/lib/xle/parse.mjs +581 -0
  81. package/src/lib/xle/print.mjs +174 -0
  82. package/src/lib/xle/registry-core.mjs +170 -0
  83. package/src/lib/xle/registry.mjs +237 -0
  84. package/src/lib/xle/splice.mjs +137 -0
  85. package/src/lib/xle/validate.mjs +356 -0
  86. package/src/lib/xle/xle.test.mjs +333 -0
  87. package/src/template.mjs +73 -0
  88. package/src/template.test.mjs +127 -0
  89. package/src/types/api.d.ts +2 -6
  90. package/src/types/base.d.ts +3 -9
  91. package/src/types/codemod.d.ts +81 -0
  92. package/src/types/component.d.ts +27 -2
  93. package/src/types/config.d.ts +70 -0
  94. package/src/types/error-codes.d.ts +5 -3
  95. package/src/types/index.d.ts +0 -1
  96. package/src/types/integration.d.ts +29 -0
  97. package/src/types/swizzle.d.ts +9 -2
  98. package/src/types/template-api.d.ts +54 -0
  99. package/src/types/template.d.ts +10 -7
  100. package/src/types/upgrade.d.ts +29 -0
  101. package/src/types/validate-integration.d.ts +24 -0
  102. package/src/utils/github.mjs +0 -252
  103. package/src/utils/interactive.mjs +2 -2
  104. package/templates/blocks/components/Card/ClickableCardWithNestedButton.doc.mjs +1 -1
  105. package/templates/blocks/components/Card/SelectableCardMulti.doc.mjs +1 -1
  106. package/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerWithProgress.tsx +1 -1
  107. package/templates/blocks/components/ChatDictationButton/ChatDictationButtonShowcase.tsx +3 -3
  108. package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.doc.mjs +15 -0
  109. package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.tsx +26 -0
  110. package/templates/blocks/components/DateInput/DateInputDateRange.doc.mjs +2 -2
  111. package/templates/blocks/components/DateRangeInput/DateRangeInputWithPresets.doc.mjs +14 -0
  112. package/templates/blocks/components/DateRangeInput/DateRangeInputWithPresets.tsx +46 -0
  113. package/templates/blocks/components/DateRangeInput/DateRangeInputWithValidation.doc.mjs +14 -0
  114. package/templates/blocks/components/DateRangeInput/DateRangeInputWithValidation.tsx +52 -0
  115. package/templates/blocks/components/DateTimeInput/DateTimeInputWithValidation.doc.mjs +14 -0
  116. package/templates/blocks/components/DateTimeInput/DateTimeInputWithValidation.tsx +43 -0
  117. package/templates/blocks/components/FileInput/FileInputShowcase.tsx +4 -2
  118. package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.doc.mjs +1 -1
  119. package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.tsx +9 -4
  120. package/templates/blocks/components/LinkProvider/LinkProviderCustomLink.doc.mjs +14 -0
  121. package/templates/blocks/components/LinkProvider/LinkProviderCustomLink.tsx +43 -0
  122. package/templates/blocks/components/MultiSelector/MultiSelectorShowcase.tsx +6 -2
  123. package/templates/blocks/components/NumberInput/NumberInputShowcase.tsx +6 -2
  124. package/templates/blocks/components/Outline/OutlineShowcase.doc.mjs +15 -0
  125. package/templates/blocks/components/Outline/OutlineShowcase.tsx +22 -0
  126. package/templates/blocks/components/RadioList/RadioListShowcase.tsx +8 -1
  127. package/templates/blocks/components/SegmentedControl/SegmentedControlShowcase.tsx +3 -1
  128. package/templates/blocks/components/Selector/SelectorShowcase.tsx +4 -1
  129. package/templates/blocks/components/Slider/SliderShowcase.tsx +10 -1
  130. package/templates/blocks/components/Tab/TabShowcase.tsx +3 -1
  131. package/templates/blocks/components/Tab/TabWithSelectedIcon.doc.mjs +13 -0
  132. package/templates/blocks/components/Tab/TabWithSelectedIcon.tsx +39 -0
  133. package/templates/blocks/components/TabList/TabListShowcase.tsx +3 -1
  134. package/templates/blocks/components/TabMenu/TabMenuShowcase.tsx +3 -1
  135. package/templates/blocks/components/Table/ColumnResizeHookUsage.doc.mjs +14 -0
  136. package/templates/blocks/components/Table/ColumnResizeHookUsage.tsx +59 -0
  137. package/templates/blocks/components/Table/StickyColumnsHookUsage.doc.mjs +14 -0
  138. package/templates/blocks/components/Table/StickyColumnsHookUsage.tsx +104 -0
  139. package/templates/blocks/components/Text/TextColors.tsx +20 -5
  140. package/templates/blocks/components/TextArea/TextAreaShowcase.tsx +4 -2
  141. package/templates/blocks/components/TextInput/TextInputShowcase.tsx +4 -2
  142. package/templates/blocks/components/Thumbnail/ThumbnailDisabled.tsx +11 -6
  143. package/templates/blocks/components/Thumbnail/ThumbnailGallery.tsx +43 -7
  144. package/templates/blocks/components/Thumbnail/ThumbnailRemovable.tsx +40 -3
  145. package/templates/blocks/components/Thumbnail/ThumbnailShowcase.tsx +6 -5
  146. package/templates/blocks/components/Thumbnail/ThumbnailStates.tsx +11 -6
  147. package/templates/blocks/components/Timestamp/TimestampColors.tsx +2 -2
  148. package/templates/blocks/components/ToggleButton/ToggleButtonGroup.doc.mjs +1 -1
  149. package/templates/blocks/components/Tokenizer/TokenizerShowcase.tsx +8 -6
  150. package/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +2 -2
  151. package/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +23 -14
  152. package/templates/blocks/components/Typeahead/TypeaheadShowcase.tsx +6 -2
  153. package/templates/pages/shell-nav/page.tsx +321 -0
  154. package/templates/pages/shell-nav/template.doc.mjs +12 -0
  155. package/templates/pages/shell-side-nav/page.tsx +242 -0
  156. package/templates/pages/shell-side-nav/template.doc.mjs +12 -0
  157. package/templates/pages/shell-top-nav/page.tsx +224 -0
  158. package/templates/pages/shell-top-nav/template.doc.mjs +12 -0
  159. package/templates/pages/theme-showcase/page.tsx +8 -19
  160. package/templates/themes/butter/butterTheme.ts +916 -0
  161. package/templates/themes/butter/icons.tsx +77 -0
  162. package/templates/themes/chocolate/chocolateTheme.ts +230 -0
  163. package/templates/themes/chocolate/icons.tsx +77 -0
  164. package/templates/themes/gothic/gothicTheme.ts +657 -0
  165. package/templates/themes/gothic/icons.tsx +77 -0
  166. package/templates/themes/manifest.json +90 -0
  167. package/templates/themes/matcha/icons.tsx +67 -0
  168. package/templates/themes/matcha/matchaTheme.ts +247 -0
  169. package/templates/themes/neutral/icons.tsx +77 -0
  170. package/templates/themes/neutral/neutralTheme.ts +603 -0
  171. package/templates/themes/stone/icons.tsx +77 -0
  172. package/templates/themes/stone/stoneTheme.ts +652 -0
  173. package/templates/themes/y2k/icons.tsx +67 -0
  174. package/templates/themes/y2k/y2kTheme.ts +617 -0
  175. package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-config-surfaces.test.mjs +0 -116
  176. package/src/codemods/transforms/v0.1.0/migrate-xds-config-surfaces.mjs +0 -230
  177. package/src/commands/gap-report.mjs +0 -456
  178. package/src/commands/gap-report.test.mjs +0 -163
  179. package/src/commands/swizzle-gap-safety.test.mjs +0 -273
  180. package/src/lib/config.mjs +0 -86
  181. package/src/lib/config.test.mjs +0 -42
  182. package/src/types/gap-report.d.ts +0 -29
  183. package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.doc.mjs +0 -14
  184. package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.tsx +0 -57
  185. /package/src/codemods/transforms/{v0.0.15 → v0.1.0}/__tests__/drop-xds-prefix-imports.test.mjs +0 -0
@@ -0,0 +1,204 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Upgrade integration error-policy + --skip-codemod tests.
5
+ *
6
+ * These scaffold a real consumer project (astryx.config.mjs + an installed
7
+ * integration package with codemods) under a REPO-LOCAL temp dir so Vite
8
+ * permits dynamic import of the config/integration modules (it blocks /tmp).
9
+ * They assert:
10
+ * - a broken integration codemod definition is SKIPPED (warned), not a hard
11
+ * fail of the upgrade (reverses the previous policy);
12
+ * - --skip-codemod excludes a named integration codemod.
13
+ */
14
+
15
+ import {describe, it, expect, beforeEach, afterEach, vi} from 'vitest';
16
+ import * as fs from 'node:fs';
17
+ import * as path from 'node:path';
18
+ import {pathToFileURL} from 'node:url';
19
+ import {Command} from 'commander';
20
+ import {registerUpgrade} from './upgrade.mjs';
21
+
22
+ let tmpDir;
23
+ let originalCwd;
24
+ let logCalls;
25
+ let errCalls;
26
+ let exitCode;
27
+
28
+ const codemodModuleUrl = pathToFileURL(
29
+ path.resolve(process.cwd(), 'packages/cli/src/codemod.mjs'),
30
+ ).href;
31
+
32
+ beforeEach(() => {
33
+ originalCwd = process.cwd();
34
+ // Repo-local temp dir: under cwd so Vite allows config/integration imports.
35
+ tmpDir = fs.mkdtempSync(path.join(process.cwd(), '.astryx-upgrade-policy-'));
36
+ process.chdir(tmpDir);
37
+ logCalls = [];
38
+ errCalls = [];
39
+ exitCode = undefined;
40
+ vi.spyOn(console, 'log').mockImplementation((...a) => logCalls.push(a.join(' ')));
41
+ vi.spyOn(console, 'error').mockImplementation((...a) => errCalls.push(a.join(' ')));
42
+ vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
43
+ vi.spyOn(process, 'exit').mockImplementation(code => {
44
+ exitCode = code;
45
+ throw new Error(`__exit ${code}`);
46
+ });
47
+ });
48
+
49
+ afterEach(() => {
50
+ process.chdir(originalCwd);
51
+ fs.rmSync(tmpDir, {recursive: true, force: true});
52
+ vi.restoreAllMocks();
53
+ });
54
+
55
+ function writeInstalledCore(version) {
56
+ const dir = path.join(tmpDir, 'node_modules', '@astryxdesign', 'core');
57
+ fs.mkdirSync(dir, {recursive: true});
58
+ fs.writeFileSync(
59
+ path.join(dir, 'package.json'),
60
+ JSON.stringify({name: '@astryxdesign/core', version}),
61
+ );
62
+ }
63
+
64
+ function writeSource() {
65
+ fs.mkdirSync(path.join(tmpDir, 'src'), {recursive: true});
66
+ fs.writeFileSync(path.join(tmpDir, 'src', 'index.ts'), 'const foo = 1;\n');
67
+ }
68
+
69
+ /**
70
+ * Scaffold a consumer + an installed integration package with codemods.
71
+ * @param {Object<string,string>} codemodFiles "<version>/<id>.mjs" -> body
72
+ */
73
+ function scaffoldIntegration(codemodFiles) {
74
+ fs.writeFileSync(
75
+ path.join(tmpDir, 'package.json'),
76
+ JSON.stringify({name: 'consumer'}),
77
+ );
78
+ fs.writeFileSync(
79
+ path.join(tmpDir, 'astryx.config.mjs'),
80
+ `export default { integrations: ['@acme/widgets'] };\n`,
81
+ );
82
+ const pkgDir = path.join(tmpDir, 'node_modules', '@acme', 'widgets');
83
+ fs.mkdirSync(pkgDir, {recursive: true});
84
+ fs.writeFileSync(
85
+ path.join(pkgDir, 'package.json'),
86
+ JSON.stringify({name: '@acme/widgets', version: '1.0.0'}),
87
+ );
88
+ fs.writeFileSync(
89
+ path.join(pkgDir, 'astryx.integration.mjs'),
90
+ `export default { codemods: './codemods' };\n`,
91
+ );
92
+ for (const [rel, body] of Object.entries(codemodFiles)) {
93
+ const full = path.join(pkgDir, 'codemods', rel);
94
+ fs.mkdirSync(path.dirname(full), {recursive: true});
95
+ fs.writeFileSync(full, body);
96
+ }
97
+ }
98
+
99
+ function createProgram() {
100
+ const program = new Command();
101
+ program.exitOverride();
102
+ program.option('--json', 'Output as typed JSON');
103
+ registerUpgrade(program);
104
+ return program;
105
+ }
106
+
107
+ async function runJson(args) {
108
+ const program = createProgram();
109
+ try {
110
+ await program.parseAsync(['node', 'astryx', ...args]);
111
+ } catch (err) {
112
+ if (!String(err?.message || '').startsWith('__exit')) throw err;
113
+ }
114
+ for (let i = logCalls.length - 1; i >= 0; i--) {
115
+ const line = logCalls[i];
116
+ if (line.startsWith('{')) {
117
+ try {
118
+ return JSON.parse(line);
119
+ } catch {
120
+ // keep looking
121
+ }
122
+ }
123
+ }
124
+ return null;
125
+ }
126
+
127
+ describe('upgrade integration error policy (skip + warn)', () => {
128
+ it('SKIPS a broken integration codemod instead of hard-failing the upgrade', async () => {
129
+ // A codemod module whose default export is not a valid codemod result —
130
+ // a DEFINITION error. The upgrade must NOT abort; it skips the broken
131
+ // integration's codemods and completes.
132
+ scaffoldIntegration({
133
+ '0.2.0/bad.mjs': `export default { not: 'a codemod' };\n`,
134
+ });
135
+ writeInstalledCore('0.2.0');
136
+ writeSource();
137
+
138
+ const result = await runJson([
139
+ '--json',
140
+ 'upgrade',
141
+ '--from',
142
+ '0.1.0',
143
+ '--path',
144
+ 'src',
145
+ ]);
146
+
147
+ // Did NOT hard-fail: no error envelope, and it ran to a status/run result.
148
+ expect(result).not.toBeNull();
149
+ expect(result.error).toBeUndefined();
150
+ expect(exitCode).not.toBe(1);
151
+ });
152
+
153
+ it('runs a healthy integration codemod for an applicable range', async () => {
154
+ scaffoldIntegration({
155
+ '0.2.0/drop-foo.mjs':
156
+ `import {createCodemod} from ${JSON.stringify(codemodModuleUrl)};\n` +
157
+ `export default createCodemod({ title: 'Drop foo', transform: (file) => file.source.replace(/foo/g, 'bar') });\n`,
158
+ });
159
+ writeInstalledCore('0.2.0');
160
+ writeSource();
161
+
162
+ const result = await runJson([
163
+ '--json',
164
+ 'upgrade',
165
+ '--from',
166
+ '0.1.0',
167
+ '--path',
168
+ 'src',
169
+ '--apply',
170
+ ]);
171
+ expect(result).not.toBeNull();
172
+ expect(result.error).toBeUndefined();
173
+ // The codemod rewrote foo -> bar.
174
+ const out = fs.readFileSync(path.join(tmpDir, 'src', 'index.ts'), 'utf-8');
175
+ expect(out).toContain('bar');
176
+ });
177
+
178
+ it('--skip-codemod excludes a named integration codemod', async () => {
179
+ scaffoldIntegration({
180
+ '0.2.0/drop-foo.mjs':
181
+ `import {createCodemod} from ${JSON.stringify(codemodModuleUrl)};\n` +
182
+ `export default createCodemod({ title: 'Drop foo', transform: (file) => file.source.replace(/foo/g, 'bar') });\n`,
183
+ });
184
+ writeInstalledCore('0.2.0');
185
+ writeSource();
186
+
187
+ const result = await runJson([
188
+ '--json',
189
+ 'upgrade',
190
+ '--from',
191
+ '0.1.0',
192
+ '--path',
193
+ 'src',
194
+ '--apply',
195
+ '--skip-codemod',
196
+ 'drop-foo',
197
+ ]);
198
+ expect(result).not.toBeNull();
199
+ // Skipped: the source is unchanged (foo not rewritten to bar).
200
+ const out = fs.readFileSync(path.join(tmpDir, 'src', 'index.ts'), 'utf-8');
201
+ expect(out).toContain('foo');
202
+ expect(out).not.toContain('bar');
203
+ });
204
+ });