@shohojdhara/atomix 0.4.7 → 0.4.9

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 (176) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +172 -157
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +4 -4
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1274 -164
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1099 -83
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2106 -1050
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1663 -638
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +442 -270
  19. package/dist/index.esm.js +1947 -680
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1982 -712
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +1 -1
  24. package/dist/index.min.js.map +1 -1
  25. package/package.json +6 -3
  26. package/scripts/atomix-cli.js +136 -1827
  27. package/scripts/cli/__tests__/basic.test.js +3 -2
  28. package/scripts/cli/__tests__/clean.test.js +278 -0
  29. package/scripts/cli/__tests__/component-validator.test.js +433 -0
  30. package/scripts/cli/__tests__/generator.test.js +613 -0
  31. package/scripts/cli/__tests__/glass-motion.test.js +256 -0
  32. package/scripts/cli/__tests__/integration.test.js +719 -108
  33. package/scripts/cli/__tests__/migrate.test.js +74 -0
  34. package/scripts/cli/__tests__/security.test.js +206 -0
  35. package/scripts/cli/__tests__/test-setup.js +3 -1
  36. package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
  37. package/scripts/cli/__tests__/token-provider.test.js +361 -0
  38. package/scripts/cli/__tests__/utils.test.js +5 -5
  39. package/scripts/cli/commands/benchmark.js +105 -0
  40. package/scripts/cli/commands/build-theme.js +115 -0
  41. package/scripts/cli/commands/clean.js +109 -0
  42. package/scripts/cli/commands/doctor.js +88 -0
  43. package/scripts/cli/commands/generate.js +218 -0
  44. package/scripts/cli/commands/init.js +73 -0
  45. package/scripts/cli/commands/migrate.js +106 -0
  46. package/scripts/cli/commands/sync-tokens.js +206 -0
  47. package/scripts/cli/commands/theme-bridge.js +248 -0
  48. package/scripts/cli/commands/tokens.js +157 -0
  49. package/scripts/cli/commands/validate.js +194 -0
  50. package/scripts/cli/internal/ai-engine.js +156 -0
  51. package/scripts/cli/internal/compiler.js +114 -0
  52. package/scripts/cli/internal/component-validator.js +443 -0
  53. package/scripts/cli/internal/config-loader.js +162 -0
  54. package/scripts/cli/internal/filesystem.js +158 -0
  55. package/scripts/cli/internal/generator.js +430 -0
  56. package/scripts/cli/internal/glass-generator.js +398 -0
  57. package/scripts/cli/internal/hook-generator.js +369 -0
  58. package/scripts/cli/internal/hooks.js +61 -0
  59. package/scripts/cli/internal/itcss-generator.js +565 -0
  60. package/scripts/cli/internal/motion-generator.js +679 -0
  61. package/scripts/cli/internal/template-engine.js +301 -0
  62. package/scripts/cli/internal/theme-bridge.js +664 -0
  63. package/scripts/cli/internal/tokens/engine.js +122 -0
  64. package/scripts/cli/internal/tokens/provider.js +34 -0
  65. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  66. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  67. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  68. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  69. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  70. package/scripts/cli/internal/validator.js +276 -0
  71. package/scripts/cli/internal/wizard.js +115 -0
  72. package/scripts/cli/mappings.js +23 -0
  73. package/scripts/cli/migration-tools.js +164 -94
  74. package/scripts/cli/plugins/style-dictionary.js +46 -0
  75. package/scripts/cli/templates/README.md +525 -95
  76. package/scripts/cli/templates/common-templates.js +40 -14
  77. package/scripts/cli/templates/components/react-component.ts +282 -0
  78. package/scripts/cli/templates/config/project-config.ts +112 -0
  79. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  80. package/scripts/cli/templates/index.js +19 -4
  81. package/scripts/cli/templates/index.ts +171 -0
  82. package/scripts/cli/templates/next-templates.js +72 -0
  83. package/scripts/cli/templates/react-templates.js +70 -126
  84. package/scripts/cli/templates/scss-templates.js +35 -35
  85. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  86. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  87. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  88. package/scripts/cli/templates/token-templates.js +337 -1
  89. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  90. package/scripts/cli/templates/types/component-types.ts +145 -0
  91. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  92. package/scripts/cli/templates/vanilla-templates.js +39 -0
  93. package/scripts/cli/token-manager.js +8 -2
  94. package/scripts/cli/utils/cache-manager.js +240 -0
  95. package/scripts/cli/utils/detector.js +46 -0
  96. package/scripts/cli/utils/diagnostics.js +289 -0
  97. package/scripts/cli/utils/error.js +89 -0
  98. package/scripts/cli/utils/helpers.js +67 -0
  99. package/scripts/cli/utils/logger.js +75 -0
  100. package/scripts/cli/utils/security.js +302 -0
  101. package/scripts/cli/utils/telemetry.js +115 -0
  102. package/scripts/cli/utils/validation.js +37 -0
  103. package/scripts/cli/utils.js +28 -341
  104. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  105. package/src/components/Accordion/Accordion.test.tsx +0 -17
  106. package/src/components/Accordion/Accordion.tsx +0 -4
  107. package/src/components/AtomixGlass/AtomixGlass.test.tsx +37 -3
  108. package/src/components/AtomixGlass/AtomixGlass.tsx +143 -31
  109. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +129 -31
  110. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  111. package/src/components/AtomixGlass/README.md +25 -10
  112. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +216 -0
  113. package/src/components/AtomixGlass/animation-system.ts +578 -0
  114. package/src/components/AtomixGlass/shader-utils.ts +4 -1
  115. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  116. package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
  117. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
  118. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
  119. package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
  120. package/src/components/Avatar/Avatar.tsx +1 -1
  121. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  122. package/src/components/Button/Button.stories.tsx +10 -0
  123. package/src/components/Button/Button.test.tsx +16 -11
  124. package/src/components/Button/Button.tsx +4 -4
  125. package/src/components/Card/Card.tsx +1 -1
  126. package/src/components/Dropdown/Dropdown.tsx +12 -12
  127. package/src/components/Form/Select.tsx +62 -3
  128. package/src/components/Modal/Modal.tsx +14 -3
  129. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  130. package/src/components/Slider/Slider.stories.tsx +3 -3
  131. package/src/components/Slider/Slider.tsx +38 -0
  132. package/src/components/Steps/Steps.tsx +3 -3
  133. package/src/components/Tabs/Tabs.tsx +77 -8
  134. package/src/components/Testimonial/Testimonial.tsx +1 -1
  135. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  136. package/src/components/TypedButton/TypedButton.tsx +39 -0
  137. package/src/components/TypedButton/index.ts +2 -0
  138. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  139. package/src/lib/composables/index.ts +4 -7
  140. package/src/lib/composables/types.ts +45 -0
  141. package/src/lib/composables/useAccordion.ts +0 -7
  142. package/src/lib/composables/useAtomixGlass.ts +148 -6
  143. package/src/lib/composables/useAtomixGlassStyles.ts +9 -7
  144. package/src/lib/composables/useChartExport.ts +3 -13
  145. package/src/lib/composables/useDropdown.ts +66 -0
  146. package/src/lib/composables/useFocusTrap.ts +80 -0
  147. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  148. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  149. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  150. package/src/lib/composables/useTooltip.ts +16 -0
  151. package/src/lib/composables/useTypedButton.ts +66 -0
  152. package/src/lib/config/index.ts +62 -5
  153. package/src/lib/constants/components.ts +62 -7
  154. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  155. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  156. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  157. package/src/lib/types/components.ts +37 -11
  158. package/src/lib/types/glass.ts +35 -0
  159. package/src/lib/types/index.ts +1 -0
  160. package/src/lib/utils/displacement-generator.ts +1 -1
  161. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  162. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  163. package/src/styles/06-components/_components.atomix-glass.scss +17 -21
  164. package/src/styles/06-components/_components.edge-panel.scss +1 -5
  165. package/src/styles/06-components/_components.modal.scss +1 -4
  166. package/src/styles/06-components/_components.navbar.scss +1 -1
  167. package/src/styles/06-components/_components.testbutton.scss +212 -0
  168. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  169. package/src/styles/06-components/_components.tooltip.scss +9 -5
  170. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  171. package/src/styles/99-utilities/_index.scss +1 -0
  172. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  173. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  174. package/scripts/cli/component-generator.js +0 -564
  175. package/scripts/cli/interactive-init.js +0 -357
  176. package/src/styles/06-components/old.chart.styles.scss +0 -2788
@@ -0,0 +1,507 @@
1
+ /**
2
+ * Tests for Theme Bridge Generator
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
6
+ import {
7
+ generateTailwindTheme,
8
+ generateCssInJsTheme,
9
+ generateCssVariables,
10
+ generateTypeScriptTypes,
11
+ validateThemeSync
12
+ } from '../internal/theme-bridge.js';
13
+ import { tokenProvider } from '../internal/tokens/token-provider.js';
14
+
15
+ // Mock filesystem
16
+ vi.mock('../internal/filesystem.js', () => ({
17
+ filesystem: {
18
+ writeFile: vi.fn().mockResolvedValue(true),
19
+ readFile: vi.fn().mockResolvedValue('mock content'),
20
+ createDirectory: vi.fn().mockResolvedValue(true)
21
+ }
22
+ }));
23
+
24
+ describe('Theme Bridge Generator', () => {
25
+ // Sample tokens for testing
26
+ const sampleTokens = {
27
+ colors: {
28
+ primary: '#3B82F6',
29
+ secondary: '#10B981',
30
+ brand: {
31
+ base: '#6366F1',
32
+ light: '#818CF8',
33
+ dark: '#4F46E5'
34
+ }
35
+ },
36
+ spacing: {
37
+ xs: '0.25rem',
38
+ sm: '0.5rem',
39
+ md: '1rem',
40
+ lg: '1.5rem',
41
+ xl: '2rem'
42
+ },
43
+ typography: {
44
+ fontFamily: {
45
+ sans: 'Inter, system-ui, sans-serif',
46
+ mono: 'Fira Code, monospace'
47
+ },
48
+ fontSize: {
49
+ sm: '0.875rem',
50
+ base: '1rem',
51
+ lg: '1.125rem',
52
+ xl: '1.25rem'
53
+ }
54
+ },
55
+ breakpoints: {
56
+ sm: '640px',
57
+ md: '768px',
58
+ lg: '1024px',
59
+ xl: '1280px'
60
+ },
61
+ shadows: {
62
+ sm: '0 1px 2px rgba(0, 0, 0, 0.05)',
63
+ md: '0 4px 6px rgba(0, 0, 0, 0.1)',
64
+ lg: '0 10px 15px rgba(0, 0, 0, 0.1)'
65
+ },
66
+ radius: {
67
+ sm: '0.25rem',
68
+ md: '0.375rem',
69
+ lg: '0.5rem',
70
+ full: '9999px'
71
+ },
72
+ zIndex: {
73
+ hidden: -1,
74
+ base: 0,
75
+ dropdown: 1000,
76
+ modal: 1500,
77
+ popover: 2000
78
+ }
79
+ };
80
+
81
+ describe('generateTailwindTheme', () => {
82
+ it('should generate valid Tailwind theme config', () => {
83
+ const config = generateTailwindTheme(sampleTokens);
84
+
85
+ expect(config).toContain('module.exports');
86
+ expect(config).toContain('theme:');
87
+ expect(config).toContain('colors:');
88
+ expect(config).toContain('spacing:');
89
+ });
90
+
91
+ it('should include all color tokens', () => {
92
+ const config = generateTailwindTheme(sampleTokens);
93
+
94
+ expect(config).toContain('primary:');
95
+ expect(config).toContain('secondary:');
96
+ expect(config).toContain('brand:');
97
+ });
98
+
99
+ it('should handle nested color objects', () => {
100
+ const config = generateTailwindTheme(sampleTokens);
101
+
102
+ expect(config).toContain('#6366F1'); // brand.base
103
+ });
104
+
105
+ it('should include spacing tokens', () => {
106
+ const config = generateTailwindTheme(sampleTokens);
107
+
108
+ expect(config).toContain('xs:');
109
+ expect(config).toContain('sm:');
110
+ expect(config).toContain('md:');
111
+ expect(config).toContain('lg:');
112
+ });
113
+
114
+ it('should include typography tokens', () => {
115
+ const config = generateTailwindTheme(sampleTokens);
116
+
117
+ expect(config).toContain('fontSize:');
118
+ expect(config).toContain('fontFamily:');
119
+ });
120
+
121
+ it('should include breakpoint tokens as screens', () => {
122
+ const config = generateTailwindTheme(sampleTokens);
123
+
124
+ expect(config).toContain('screens:');
125
+ expect(config).toContain('sm:');
126
+ expect(config).toContain('md:');
127
+ });
128
+
129
+ it('should include shadow tokens', () => {
130
+ const config = generateTailwindTheme(sampleTokens);
131
+
132
+ expect(config).toContain('boxShadow:');
133
+ expect(config).toContain('sm:');
134
+ });
135
+
136
+ it('should include border radius tokens', () => {
137
+ const config = generateTailwindTheme(sampleTokens);
138
+
139
+ expect(config).toContain('borderRadius:');
140
+ expect(config).toContain('full:');
141
+ });
142
+
143
+ it('should generate valid JavaScript syntax', () => {
144
+ const config = generateTailwindTheme(sampleTokens);
145
+
146
+ // Basic syntax validation
147
+ expect(config).toContain('{');
148
+ expect(config).toContain('}');
149
+ expect(config.split('{').length).toBeGreaterThan(1);
150
+ });
151
+ });
152
+
153
+ describe('generateCssInJsTheme', () => {
154
+ it('should generate emotion theme by default', () => {
155
+ const theme = generateCssInJsTheme(sampleTokens, 'emotion');
156
+
157
+ expect(theme).toContain('export const theme');
158
+ expect(theme).toContain('colors:');
159
+ expect(theme).toContain('space:');
160
+ });
161
+
162
+ it('should generate styled-components theme', () => {
163
+ const theme = generateCssInJsTheme(sampleTokens, 'styled-components');
164
+
165
+ expect(theme).toContain('export const theme');
166
+ expect(theme).toContain('fonts:');
167
+ });
168
+
169
+ it('should generate vanilla-extract theme with imports', () => {
170
+ const theme = generateCssInJsTheme(sampleTokens, 'vanilla-extract');
171
+
172
+ expect(theme).toContain("import { createGlobalTheme }");
173
+ expect(theme).toContain('createGlobalTheme');
174
+ expect(theme).toContain('export type Theme');
175
+ });
176
+
177
+ it('should include all token categories', () => {
178
+ const theme = generateCssInJsTheme(sampleTokens, 'emotion');
179
+
180
+ expect(theme).toContain('colors:');
181
+ expect(theme).toContain('space:');
182
+ expect(theme).toContain('fonts:');
183
+ expect(theme).toContain('fontSizes:');
184
+ expect(theme).toContain('breakpoints:');
185
+ expect(theme).toContain('shadows:');
186
+ expect(theme).toContain('radii:');
187
+ });
188
+
189
+ it('should handle nested color values', () => {
190
+ const theme = generateCssInJsTheme(sampleTokens, 'emotion');
191
+
192
+ expect(theme).toContain('base:');
193
+ expect(theme).toContain('light:');
194
+ expect(theme).toContain('dark:');
195
+ });
196
+
197
+ it('should include z-index tokens', () => {
198
+ const theme = generateCssInJsTheme(sampleTokens, 'emotion');
199
+
200
+ expect(theme).toContain('zIndices:');
201
+ expect(theme).toContain('modal:');
202
+ });
203
+ });
204
+
205
+ describe('generateCssVariables', () => {
206
+ it('should generate CSS custom properties in :root', () => {
207
+ const css = generateCssVariables(sampleTokens);
208
+
209
+ expect(css).toContain(':root {');
210
+ expect(css).toContain('--atomix-');
211
+ });
212
+
213
+ it('should use custom selector when provided', () => {
214
+ const css = generateCssVariables(sampleTokens, { selector: '[data-theme]' });
215
+
216
+ expect(css).toContain('[data-theme] {');
217
+ });
218
+
219
+ it('should use custom prefix when provided', () => {
220
+ const css = generateCssVariables(sampleTokens, { prefix: 'custom' });
221
+
222
+ expect(css).toContain('--custom-');
223
+ });
224
+
225
+ it('should generate color variables', () => {
226
+ const css = generateCssVariables(sampleTokens);
227
+
228
+ expect(css).toContain('--atomix-primary:');
229
+ expect(css).toContain('--atomix-secondary:');
230
+ });
231
+
232
+ it('should handle nested color objects', () => {
233
+ const css = generateCssVariables(sampleTokens);
234
+
235
+ expect(css).toContain('--atomix-brand:'); // Uses base value for main variable
236
+ expect(css).toContain('--atomix-brand-light:');
237
+ expect(css).toContain('--atomix-brand-dark:');
238
+ });
239
+
240
+ it('should generate spacing variables', () => {
241
+ const css = generateCssVariables(sampleTokens);
242
+
243
+ expect(css).toContain('--atomix-space-xs:');
244
+ expect(css).toContain('--atomix-space-sm:');
245
+ });
246
+
247
+ it('should generate font variables', () => {
248
+ const css = generateCssVariables(sampleTokens);
249
+
250
+ expect(css).toContain('--atomix-font-sans:');
251
+ expect(css).toContain('--atomix-text-base:');
252
+ });
253
+
254
+ it('should generate breakpoint variables', () => {
255
+ const css = generateCssVariables(sampleTokens);
256
+
257
+ expect(css).toContain('--atomix-breakpoint-sm:');
258
+ expect(css).toContain('--atomix-breakpoint-md:');
259
+ });
260
+
261
+ it('should generate shadow variables', () => {
262
+ const css = generateCssVariables(sampleTokens);
263
+
264
+ expect(css).toContain('--atomix-shadow-sm:');
265
+ expect(css).toContain('--atomix-shadow-md:');
266
+ });
267
+
268
+ it('should generate radius variables', () => {
269
+ const css = generateCssVariables(sampleTokens);
270
+
271
+ expect(css).toContain('--atomix-radius-sm:');
272
+ expect(css).toContain('--atomix-radius-full:');
273
+ });
274
+
275
+ it('should generate z-index variables', () => {
276
+ const css = generateCssVariables(sampleTokens);
277
+
278
+ expect(css).toContain('--atomix-z-modal:');
279
+ expect(css).toContain('--atomix-z-popover:');
280
+ });
281
+
282
+ it('should close the selector block', () => {
283
+ const css = generateCssVariables(sampleTokens);
284
+
285
+ expect(css).toMatch(/\}$/);
286
+ });
287
+ });
288
+
289
+ describe('generateTypeScriptTypes', () => {
290
+ it('should generate TypeScript interface', () => {
291
+ const types = generateTypeScriptTypes(sampleTokens);
292
+
293
+ expect(types).toContain('export interface AtomixTheme');
294
+ });
295
+
296
+ it('should include JSDoc header', () => {
297
+ const types = generateTypeScriptTypes(sampleTokens);
298
+
299
+ expect(types).toContain('/**');
300
+ expect(types).toContain('Auto-generated from design tokens');
301
+ });
302
+
303
+ it('should generate color type definitions', () => {
304
+ const types = generateTypeScriptTypes(sampleTokens);
305
+
306
+ expect(types).toContain('colors:');
307
+ expect(types).toContain('primary: string;');
308
+ });
309
+
310
+ it('should generate spacing type definitions', () => {
311
+ const types = generateTypeScriptTypes(sampleTokens);
312
+
313
+ expect(types).toContain('space:');
314
+ expect(types).toContain('sm: string;');
315
+ });
316
+
317
+ it('should generate utility type aliases', () => {
318
+ const types = generateTypeScriptTypes(sampleTokens);
319
+
320
+ expect(types).toContain('export type ThemeColor');
321
+ expect(types).toContain('export type ThemeSpacing');
322
+ expect(types).toContain('export type ThemeFontSize');
323
+ });
324
+
325
+ it('should use correct types for different token categories', () => {
326
+ const types = generateTypeScriptTypes(sampleTokens);
327
+
328
+ // String types
329
+ expect(types).toContain(': string;');
330
+
331
+ // Number types for zIndex
332
+ expect(types).toContain(': number;');
333
+ });
334
+ });
335
+
336
+ describe('validateThemeSync', () => {
337
+ it('should return valid when all tokens are present', async () => {
338
+ // Mock tokenProvider.loadTokens
339
+ const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockResolvedValue({
340
+ colors: { primary: '#3B82F6', secondary: '#10B981' },
341
+ spacing: { sm: '0.5rem', md: '1rem' }
342
+ });
343
+
344
+ const mockThemeContent = `
345
+ export const theme = {
346
+ colors: { primary: '#3B82F6', secondary: '#10B981' },
347
+ space: { sm: '0.5rem', md: '1rem' }
348
+ };
349
+ `;
350
+
351
+ // Mock filesystem.readFile
352
+ const { filesystem } = await import('../internal/filesystem.js');
353
+ const readFileSpy = vi.spyOn(filesystem, 'readFile').mockResolvedValue(mockThemeContent);
354
+
355
+ const result = await validateThemeSync(
356
+ './tokens.json',
357
+ './theme.ts',
358
+ 'css-in-js'
359
+ );
360
+
361
+ expect(result.valid).toBe(true);
362
+ expect(result.issues).toEqual([]);
363
+ expect(result.tokensChecked).toBeGreaterThan(0);
364
+
365
+ loadTokensSpy.mockRestore();
366
+ readFileSpy.mockRestore();
367
+ });
368
+
369
+ it('should detect missing tokens', async () => {
370
+ const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockResolvedValue({
371
+ colors: { primary: '#3B82F6', secondary: '#10B981' },
372
+ spacing: { sm: '0.5rem', md: '1rem' }
373
+ });
374
+
375
+ const mockThemeContent = `
376
+ export const theme = {
377
+ colors: { primary: '#3B82F6' }
378
+ };
379
+ `;
380
+
381
+ const { filesystem } = await import('../internal/filesystem.js');
382
+ const readFileSpy = vi.spyOn(filesystem, 'readFile').mockResolvedValue(mockThemeContent);
383
+
384
+ const result = await validateThemeSync(
385
+ './tokens.json',
386
+ './theme.ts',
387
+ 'css-in-js'
388
+ );
389
+
390
+ // Should have issues for missing tokens
391
+ expect(result.issues).toBeDefined();
392
+ expect(result.issues.length).toBeGreaterThan(0);
393
+
394
+ loadTokensSpy.mockRestore();
395
+ readFileSpy.mockRestore();
396
+ });
397
+
398
+ it('should validate Tailwind CommonJS exports', async () => {
399
+ const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockResolvedValue({
400
+ colors: { primary: '#3B82F6' }
401
+ });
402
+
403
+ const invalidTailwind = `
404
+ export default { theme: {} };
405
+ `;
406
+
407
+ const { filesystem } = await import('../internal/filesystem.js');
408
+ const readFileSpy = vi.spyOn(filesystem, 'readFile').mockResolvedValue(invalidTailwind);
409
+
410
+ const result = await validateThemeSync(
411
+ './tokens.json',
412
+ './tailwind.config.js',
413
+ 'tailwind'
414
+ );
415
+
416
+ expect(result.valid).toBe(false);
417
+ expect(result.issues.some(i => i.severity === 'error')).toBe(true);
418
+
419
+ loadTokensSpy.mockRestore();
420
+ readFileSpy.mockRestore();
421
+ });
422
+
423
+ it('should validate CSS variables :root selector', async () => {
424
+ const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockResolvedValue({
425
+ colors: { primary: '#3B82F6' }
426
+ });
427
+
428
+ const invalidCss = `
429
+ .theme { --atomix-primary: #3B82F6; }
430
+ `;
431
+
432
+ const { filesystem } = await import('../internal/filesystem.js');
433
+ const readFileSpy = vi.spyOn(filesystem, 'readFile').mockResolvedValue(invalidCss);
434
+
435
+ const result = await validateThemeSync(
436
+ './tokens.json',
437
+ './variables.css',
438
+ 'css-variables'
439
+ );
440
+
441
+ expect(result.valid).toBe(false);
442
+ expect(result.issues.some(i => i.severity === 'error')).toBe(true);
443
+
444
+ loadTokensSpy.mockRestore();
445
+ readFileSpy.mockRestore();
446
+ });
447
+
448
+ it('should handle validation errors gracefully', async () => {
449
+ const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockRejectedValue(
450
+ new Error('File not found')
451
+ );
452
+
453
+ const result = await validateThemeSync(
454
+ './nonexistent.json',
455
+ './nonexistent.ts',
456
+ 'css-in-js'
457
+ );
458
+
459
+ expect(result.valid).toBe(false);
460
+ expect(result.issues).toBeDefined();
461
+ expect(result.issues.length).toBeGreaterThan(0);
462
+
463
+ loadTokensSpy.mockRestore();
464
+ });
465
+ });
466
+
467
+ describe('Integration Scenarios', () => {
468
+ it('should handle empty tokens object', () => {
469
+ const emptyTokens = {};
470
+
471
+ const tailwind = generateTailwindTheme(emptyTokens);
472
+ const cssInJs = generateCssInJsTheme(emptyTokens, 'emotion');
473
+ const cssVars = generateCssVariables(emptyTokens);
474
+
475
+ expect(tailwind).toBeDefined();
476
+ expect(cssInJs).toBeDefined();
477
+ expect(cssVars).toBeDefined();
478
+ });
479
+
480
+ it('should handle partial tokens (missing categories)', () => {
481
+ const partialTokens = {
482
+ colors: { primary: '#FF0000' }
483
+ // Missing other categories
484
+ };
485
+
486
+ const tailwind = generateTailwindTheme(partialTokens);
487
+
488
+ expect(tailwind).toContain('colors:');
489
+ expect(tailwind).not.toContain('spacing:');
490
+ });
491
+
492
+ it('should preserve token naming conventions', () => {
493
+ const semanticTokens = {
494
+ colors: {
495
+ 'button-primary': '#3B82F6',
496
+ 'text-muted': '#6B7280',
497
+ 'bg-surface': '#FFFFFF'
498
+ }
499
+ };
500
+
501
+ const css = generateCssVariables(semanticTokens);
502
+
503
+ expect(css).toContain('--atomix-button-primary');
504
+ expect(css).toContain('--atomix-text-muted');
505
+ });
506
+ });
507
+ });