@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,74 @@
1
+ /**
2
+ * Migrate Command Unit Tests
3
+ * Tests ensureSourceIsDirectory behavior and migrate error paths
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { mkdtemp, rm, writeFile } from 'fs/promises';
8
+ import { join } from 'path';
9
+ import { tmpdir } from 'os';
10
+ import { migrateAction } from '../commands/migrate.js';
11
+ import { AtomixCLIError, ErrorCategory } from '../utils/error.js';
12
+
13
+ describe('Migrate Command', () => {
14
+ let tempDir;
15
+ let originalCwd;
16
+
17
+ beforeEach(async () => {
18
+ tempDir = await mkdtemp(join(tmpdir(), 'atomix-migrate-test-'));
19
+ originalCwd = process.cwd();
20
+ process.chdir(tempDir);
21
+ });
22
+
23
+ afterEach(async () => {
24
+ process.chdir(originalCwd);
25
+ await rm(tempDir, { recursive: true, force: true });
26
+ vi.restoreAllMocks();
27
+ });
28
+
29
+ describe('ensureSourceIsDirectory (via migrateAction)', () => {
30
+ it('should throw INVALID_PATH when source does not exist', async () => {
31
+ await expect(
32
+ migrateAction('tailwind', './nonexistent-dir-xyz-123')
33
+ ).rejects.toThrow(AtomixCLIError);
34
+
35
+ try {
36
+ await migrateAction('tailwind', './nonexistent-dir-xyz-123');
37
+ } catch (err) {
38
+ expect(err.code).toBe(ErrorCategory.INVALID_PATH);
39
+ expect(err.message).toContain('Source not found');
40
+ }
41
+ });
42
+
43
+ it('should throw INVALID_PATH when source is a file not a directory', async () => {
44
+ const filePath = join(tempDir, 'package.json');
45
+ await writeFile(filePath, '{}');
46
+ const relativeFile = 'package.json';
47
+
48
+ await expect(
49
+ migrateAction('tailwind', relativeFile)
50
+ ).rejects.toThrow(AtomixCLIError);
51
+
52
+ try {
53
+ await migrateAction('tailwind', relativeFile);
54
+ } catch (err) {
55
+ expect(err.code).toBe(ErrorCategory.INVALID_PATH);
56
+ expect(err.message).toContain('not a directory');
57
+ }
58
+ });
59
+
60
+ it('should throw when migration type is unsupported', async () => {
61
+ let threw = false;
62
+ try {
63
+ await migrateAction('unknown-framework', '.');
64
+ } catch (err) {
65
+ threw = true;
66
+ if (err instanceof AtomixCLIError) {
67
+ expect(err.code).toBe(ErrorCategory.VALIDATION);
68
+ expect(err.message).toContain('Unsupported migration type');
69
+ }
70
+ }
71
+ expect(threw).toBe(true);
72
+ });
73
+ });
74
+ });
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Security-focused tests for Atomix CLI
3
+ * Tests path traversal prevention, input sanitization, and security features
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import {
8
+ sanitizeInput,
9
+ validateSecurePath,
10
+ validateComponentNameSecure,
11
+ SecurityError,
12
+ RateLimiter
13
+ } from '../utils/security.js';
14
+ import { filesystem } from '../internal/filesystem.js';
15
+
16
+ // Mock filesystem operations to avoid actual file I/O
17
+ vi.mock('../internal/filesystem.js', () => ({
18
+ filesystem: {
19
+ writeFile: vi.fn(),
20
+ exists: vi.fn()
21
+ }
22
+ }));
23
+
24
+ describe('Security Utilities', () => {
25
+ describe('sanitizeInput', () => {
26
+ it('should sanitize filename inputs', () => {
27
+ const malicious = '../../etc/passwd';
28
+ const sanitized = sanitizeInput(malicious, 'filename');
29
+ expect(sanitized).not.toContain('..');
30
+ expect(sanitized).not.toContain('/');
31
+ });
32
+
33
+ it('should sanitize component names', () => {
34
+ const malicious = 'Button<script>alert(1)</script>';
35
+ const sanitized = sanitizeInput(malicious, 'componentName');
36
+ expect(sanitized).toMatch(/^[A-Z][a-zA-Z0-9]*$/);
37
+ expect(sanitized).not.toContain('<');
38
+ expect(sanitized).not.toContain('>');
39
+ });
40
+
41
+ it('should sanitize AI prompts', () => {
42
+ const malicious = 'Create a component that executes <script>malicious()</script>';
43
+ const sanitized = sanitizeInput(malicious, 'prompt');
44
+ expect(sanitized).not.toContain('<script>');
45
+ expect(sanitized).not.toContain('</script>');
46
+ });
47
+
48
+ it('should handle empty inputs', () => {
49
+ expect(() => sanitizeInput('', 'filename')).toThrow();
50
+ });
51
+ });
52
+
53
+ describe('validateSecurePath', () => {
54
+ it('should prevent path traversal attacks', () => {
55
+ const result = validateSecurePath('../../etc/passwd', '/safe/dir');
56
+ expect(result.isValid).toBe(false);
57
+ expect(result.error).toContain('Path traversal');
58
+ });
59
+
60
+ it('should prevent access to system directories', () => {
61
+ const result = validateSecurePath('/etc/passwd', '/safe/dir');
62
+ expect(result.isValid).toBe(false);
63
+ expect(result.error).toMatch(/Path traversal|system directories/);
64
+ });
65
+
66
+ it('should allow valid relative paths', () => {
67
+ const result = validateSecurePath('./src/components', process.cwd());
68
+ expect(result.isValid).toBe(true);
69
+ });
70
+
71
+ it('should allow valid absolute paths within project', () => {
72
+ const result = validateSecurePath(process.cwd() + '/src/components', process.cwd());
73
+ expect(result.isValid).toBe(true);
74
+ });
75
+ });
76
+
77
+ describe('validateComponentNameSecure', () => {
78
+ it('should reject malicious or reserved component names', () => {
79
+ const maliciousNames = [
80
+ 'eval',
81
+ 'script',
82
+ 'javascript',
83
+ 'onload',
84
+ 'onerror',
85
+ 'Button<script>'
86
+ ];
87
+
88
+ maliciousNames.forEach(name => {
89
+ const result = validateComponentNameSecure(name);
90
+ expect(result.isValid).toBe(false);
91
+ expect(result.error).toBeTruthy();
92
+ });
93
+ });
94
+
95
+ it('should accept valid component names', () => {
96
+ const validNames = [
97
+ 'Button',
98
+ 'CardHeader',
99
+ 'ModalDialog',
100
+ 'AccordionItem'
101
+ ];
102
+
103
+ validNames.forEach(name => {
104
+ const result = validateComponentNameSecure(name);
105
+ expect(result.isValid).toBe(true);
106
+ });
107
+ });
108
+
109
+ it('should reject reserved words', () => {
110
+ const reservedNames = ['Component', 'React', 'Fragment', 'Window'];
111
+ reservedNames.forEach(name => {
112
+ const result = validateComponentNameSecure(name);
113
+ expect(result.isValid).toBe(false);
114
+ });
115
+ });
116
+ });
117
+
118
+ describe('RateLimiter', () => {
119
+ let rateLimiter;
120
+
121
+ beforeEach(() => {
122
+ rateLimiter = new RateLimiter(2, 1000); // 2 requests per second
123
+ });
124
+
125
+ it('should enforce rate limits', () => {
126
+ expect(rateLimiter.checkLimit('user1')).toBe(true);
127
+ expect(rateLimiter.checkLimit('user1')).toBe(true);
128
+ expect(rateLimiter.checkLimit('user1')).toBe(false); // Third request should be blocked
129
+ });
130
+
131
+ it('should track different users separately', () => {
132
+ expect(rateLimiter.checkLimit('user1')).toBe(true);
133
+ expect(rateLimiter.checkLimit('user2')).toBe(true);
134
+ expect(rateLimiter.checkLimit('user1')).toBe(true);
135
+ expect(rateLimiter.checkLimit('user2')).toBe(true);
136
+ expect(rateLimiter.checkLimit('user1')).toBe(false);
137
+ expect(rateLimiter.checkLimit('user2')).toBe(false);
138
+ });
139
+
140
+ it('should reset after time window', async () => {
141
+ expect(rateLimiter.checkLimit('user1')).toBe(true);
142
+ expect(rateLimiter.checkLimit('user1')).toBe(true);
143
+ expect(rateLimiter.checkLimit('user1')).toBe(false);
144
+
145
+ await new Promise(resolve => setTimeout(resolve, 1100)); // Wait longer than time window
146
+
147
+ expect(rateLimiter.checkLimit('user1')).toBe(true); // Should work again
148
+ });
149
+ });
150
+
151
+ describe('Filesystem Security', () => {
152
+ it('should reject path traversal via validateSecurePath', () => {
153
+ const result = validateSecurePath('../../etc/passwd', process.cwd());
154
+ expect(result.isValid).toBe(false);
155
+ expect(result.error).toBeTruthy();
156
+ });
157
+ });
158
+ });
159
+
160
+ describe('Path Traversal Prevention', () => {
161
+ const testCases = [
162
+ { input: '../../etc/passwd', expected: false },
163
+ { input: '/etc/passwd', expected: false },
164
+ { input: '..\\Windows\\System32', expected: false },
165
+ { input: 'normal/path', expected: true },
166
+ { input: './src/components', expected: true },
167
+ { input: 'src/components/Button', expected: true },
168
+ { input: '../' + process.cwd() + '/src', expected: false }, // Relative traversal
169
+ { input: process.cwd() + '/../../etc', expected: false }, // Absolute traversal
170
+ ];
171
+
172
+ testCases.forEach(({ input, expected }) => {
173
+ it(`should ${expected ? 'allow' : 'block'} path: ${input}`, () => {
174
+ const result = validateSecurePath(input, process.cwd());
175
+ expect(result.isValid).toBe(expected);
176
+
177
+ if (!expected) {
178
+ expect(result.error).toBeDefined();
179
+ }
180
+ });
181
+ });
182
+ });
183
+
184
+ describe('Input Sanitization Edge Cases', () => {
185
+ const edgeCases = [
186
+ { input: null, type: 'filename', shouldThrow: true },
187
+ { input: undefined, type: 'filename', shouldThrow: true },
188
+ { input: '', type: 'filename', shouldThrow: true },
189
+ { input: ' ', type: 'filename', shouldThrow: true },
190
+ { input: 'normal', type: 'filename', expected: 'normal' },
191
+ { input: 'file\x00name', type: 'filename', expected: 'filename' },
192
+ { input: 'file\nname', type: 'filename', expected: 'filename' },
193
+ { input: 'file<script>', type: 'filename', expected: 'filescript' },
194
+ ];
195
+
196
+ edgeCases.forEach(({ input, type, expected, shouldThrow }) => {
197
+ it(`should handle ${JSON.stringify(input)} for ${type}`, () => {
198
+ if (shouldThrow) {
199
+ expect(() => sanitizeInput(input, type)).toThrow();
200
+ } else {
201
+ const result = sanitizeInput(input, type);
202
+ expect(result).toBe(expected);
203
+ }
204
+ });
205
+ });
206
+ });
@@ -27,11 +27,13 @@ vi.mock('chalk', () => ({
27
27
  yellow: vi.fn((text) => text),
28
28
  cyan: vi.fn((text) => text),
29
29
  gray: vi.fn((text) => text),
30
+ blue: vi.fn((text) => text),
30
31
  bold: {
31
32
  green: vi.fn((text) => text),
32
33
  red: vi.fn((text) => text),
33
34
  yellow: vi.fn((text) => text),
34
- cyan: vi.fn((text) => text)
35
+ cyan: vi.fn((text) => text),
36
+ blue: vi.fn((text) => text)
35
37
  }
36
38
  }
37
39
  }));