@shohojdhara/atomix 0.4.9 → 0.5.1

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 (67) hide show
  1. package/dist/atomix.css +95 -69
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +1 -1
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/charts.d.ts +1 -0
  6. package/dist/charts.js +231 -332
  7. package/dist/charts.js.map +1 -1
  8. package/dist/core.d.ts +1 -0
  9. package/dist/core.js +232 -333
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.d.ts +1 -0
  12. package/dist/forms.js +231 -332
  13. package/dist/forms.js.map +1 -1
  14. package/dist/heavy.d.ts +11 -2
  15. package/dist/heavy.js +233 -334
  16. package/dist/heavy.js.map +1 -1
  17. package/dist/index.d.ts +13 -2
  18. package/dist/index.esm.js +228 -327
  19. package/dist/index.esm.js.map +1 -1
  20. package/dist/index.js +227 -326
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.min.js +1 -1
  23. package/dist/index.min.js.map +1 -1
  24. package/package.json +11 -1
  25. package/src/components/AtomixGlass/AtomixGlass.tsx +188 -128
  26. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +62 -90
  27. package/src/components/AtomixGlass/PerformanceDashboard.tsx +153 -201
  28. package/src/components/AtomixGlass/glass-utils.ts +50 -0
  29. package/src/components/AtomixGlass/shader-utils.ts +1 -1
  30. package/src/components/AtomixGlass/stories/{Phase1-Animation.stories.tsx → AnimationFeatures.stories.tsx} +53 -47
  31. package/src/components/AtomixGlass/stories/Examples.stories.tsx +573 -236
  32. package/src/components/AtomixGlass/stories/Playground.stories.tsx +656 -44
  33. package/src/components/AtomixGlass/stories/argTypes.ts +384 -0
  34. package/src/components/AtomixGlass/stories/shared-components.tsx +82 -3
  35. package/src/components/AtomixGlass/stories/types.ts +127 -0
  36. package/src/lib/composables/useAtomixGlass.ts +108 -71
  37. package/src/lib/composables/useAtomixGlassStyles.ts +0 -2
  38. package/src/lib/constants/components.ts +1 -0
  39. package/src/lib/types/components.ts +1 -0
  40. package/src/lib/utils/displacement-generator.ts +1 -1
  41. package/src/styles/06-components/_components.atomix-glass.scss +158 -97
  42. package/scripts/cli/__tests__/README.md +0 -81
  43. package/scripts/cli/__tests__/basic.test.js +0 -116
  44. package/scripts/cli/__tests__/clean.test.js +0 -278
  45. package/scripts/cli/__tests__/component-generator.test.js +0 -332
  46. package/scripts/cli/__tests__/component-validator.test.js +0 -433
  47. package/scripts/cli/__tests__/generator.test.js +0 -613
  48. package/scripts/cli/__tests__/glass-motion.test.js +0 -256
  49. package/scripts/cli/__tests__/integration.test.js +0 -938
  50. package/scripts/cli/__tests__/migrate.test.js +0 -74
  51. package/scripts/cli/__tests__/security.test.js +0 -206
  52. package/scripts/cli/__tests__/test-setup.js +0 -135
  53. package/scripts/cli/__tests__/theme-bridge.test.js +0 -507
  54. package/scripts/cli/__tests__/token-manager.test.js +0 -251
  55. package/scripts/cli/__tests__/token-provider.test.js +0 -361
  56. package/scripts/cli/__tests__/utils.test.js +0 -165
  57. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +0 -216
  58. package/src/components/AtomixGlass/stories/Customization.stories.tsx +0 -131
  59. package/src/components/AtomixGlass/stories/Modes.stories.tsx +0 -1082
  60. package/src/components/AtomixGlass/stories/Overview.stories.tsx +0 -497
  61. package/src/components/AtomixGlass/stories/Performance.stories.tsx +0 -103
  62. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +0 -95
  63. package/src/components/AtomixGlass/stories/Shaders.stories.tsx +0 -395
  64. package/src/components/TypedButton/TypedButton.stories.tsx +0 -59
  65. package/src/components/TypedButton/TypedButton.tsx +0 -39
  66. package/src/components/TypedButton/index.ts +0 -2
  67. package/src/lib/composables/useTypedButton.ts +0 -66
@@ -1,74 +0,0 @@
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
- });
@@ -1,206 +0,0 @@
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
- });
@@ -1,135 +0,0 @@
1
- /**
2
- * Test Setup for CLI Tests
3
- */
4
-
5
- import { vi } from 'vitest';
6
-
7
- // Mock external dependencies
8
- vi.mock('ora', () => ({
9
- default: vi.fn(() => ({
10
- start: vi.fn(() => ({
11
- succeed: vi.fn(),
12
- fail: vi.fn(),
13
- stop: vi.fn(),
14
- text: ''
15
- }))
16
- }))
17
- }));
18
-
19
- vi.mock('inquirer', () => ({
20
- prompt: vi.fn()
21
- }));
22
-
23
- vi.mock('chalk', () => ({
24
- default: {
25
- green: vi.fn((text) => text),
26
- red: vi.fn((text) => text),
27
- yellow: vi.fn((text) => text),
28
- cyan: vi.fn((text) => text),
29
- gray: vi.fn((text) => text),
30
- blue: vi.fn((text) => text),
31
- bold: {
32
- green: vi.fn((text) => text),
33
- red: vi.fn((text) => text),
34
- yellow: vi.fn((text) => text),
35
- cyan: vi.fn((text) => text),
36
- blue: vi.fn((text) => text)
37
- }
38
- }
39
- }));
40
-
41
- vi.mock('boxen', () => ({
42
- default: vi.fn((text) => text)
43
- }));
44
-
45
- vi.mock('chokidar', () => ({
46
- default: vi.fn(() => ({
47
- on: vi.fn(),
48
- close: vi.fn()
49
- }))
50
- }));
51
-
52
- // Mock file system operations
53
- vi.mock('fs/promises', async () => {
54
- const actual = await vi.importActual('fs/promises');
55
- return {
56
- ...actual,
57
- writeFile: vi.fn(actual.writeFile),
58
- readFile: vi.fn(actual.readFile),
59
- mkdir: vi.fn(actual.mkdir),
60
- access: vi.fn(actual.access),
61
- stat: vi.fn(actual.stat),
62
- rm: vi.fn(actual.rm)
63
- };
64
- });
65
-
66
- // Mock process.cwd for consistent test environment
67
- const originalCwd = process.cwd;
68
-
69
- beforeEach(() => {
70
- // Reset all mocks before each test
71
- vi.clearAllMocks();
72
- });
73
-
74
- afterEach(() => {
75
- // Restore original process.cwd
76
- process.cwd = originalCwd;
77
- });
78
-
79
- // Global test utilities
80
- global.createMockTempDir = () => '/tmp/atomix-test-' + Math.random().toString(36).substr(2, 9);
81
-
82
- global.mockComponentStructure = (componentName, content = '') => ({
83
- [`${componentName}.tsx`]: content || `
84
- import React, { forwardRef } from 'react';
85
-
86
- export const ${componentName} = forwardRef<HTMLDivElement, ${componentName}Props>(
87
- ({ children, className = '', ...props }, ref) => {
88
- return (
89
- <div ref={ref} className={className} {...props}>
90
- {children}
91
- </div>
92
- );
93
- }
94
- );
95
-
96
- interface ${componentName}Props {
97
- children?: React.ReactNode;
98
- className?: string;
99
- }
100
- `,
101
- 'index.ts': `export { ${componentName} } from './${componentName}';`,
102
- [`${componentName}.stories.tsx`]: `
103
- import type { Meta, StoryObj } from '@storybook/react';
104
- import { ${componentName} } from './${componentName}';
105
-
106
- const meta: Meta<typeof ${componentName}> = {
107
- title: 'Components/${componentName}',
108
- component: ${componentName},
109
- parameters: {
110
- layout: 'centered',
111
- },
112
- tags: ['autodocs'],
113
- };
114
-
115
- export default meta;
116
- type Story = StoryObj<typeof meta>;
117
-
118
- export const Default: Story = {
119
- args: {
120
- children: 'Test ${componentName}',
121
- },
122
- };
123
- `,
124
- [`${componentName}.test.tsx`]: `
125
- import { render, screen } from '@testing-library/react';
126
- import { ${componentName} } from './${componentName}';
127
-
128
- describe('${componentName}', () => {
129
- it('renders correctly', () => {
130
- render(<${componentName}>Test</${componentName}>);
131
- expect(screen.getByText('Test')).toBeInTheDocument();
132
- });
133
- });
134
- `
135
- });