@shohojdhara/atomix 0.4.8 → 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 (165) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +148 -120
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +1 -1
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1227 -122
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1052 -41
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2086 -1035
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1620 -600
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +441 -270
  19. package/dist/index.esm.js +1900 -638
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1935 -670
  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 +148 -4
  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 +4 -1
  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 +135 -14
  44. package/scripts/cli/commands/init.js +45 -18
  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/component-validator.js +443 -0
  52. package/scripts/cli/internal/config-loader.js +162 -0
  53. package/scripts/cli/internal/filesystem.js +102 -2
  54. package/scripts/cli/internal/generator.js +359 -39
  55. package/scripts/cli/internal/glass-generator.js +398 -0
  56. package/scripts/cli/internal/hook-generator.js +369 -0
  57. package/scripts/cli/internal/hooks.js +61 -0
  58. package/scripts/cli/internal/itcss-generator.js +565 -0
  59. package/scripts/cli/internal/motion-generator.js +679 -0
  60. package/scripts/cli/internal/template-engine.js +301 -0
  61. package/scripts/cli/internal/theme-bridge.js +664 -0
  62. package/scripts/cli/internal/tokens/engine.js +122 -0
  63. package/scripts/cli/internal/tokens/provider.js +34 -0
  64. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  65. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  66. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  67. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  68. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  69. package/scripts/cli/internal/validator.js +276 -0
  70. package/scripts/cli/internal/wizard.js +60 -6
  71. package/scripts/cli/mappings.js +23 -0
  72. package/scripts/cli/migration-tools.js +164 -94
  73. package/scripts/cli/plugins/style-dictionary.js +46 -0
  74. package/scripts/cli/templates/README.md +525 -95
  75. package/scripts/cli/templates/common-templates.js +40 -14
  76. package/scripts/cli/templates/components/react-component.ts +282 -0
  77. package/scripts/cli/templates/config/project-config.ts +112 -0
  78. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  79. package/scripts/cli/templates/index.js +19 -4
  80. package/scripts/cli/templates/index.ts +171 -0
  81. package/scripts/cli/templates/next-templates.js +72 -0
  82. package/scripts/cli/templates/react-templates.js +70 -126
  83. package/scripts/cli/templates/scss-templates.js +35 -35
  84. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  85. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  86. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  87. package/scripts/cli/templates/token-templates.js +337 -1
  88. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  89. package/scripts/cli/templates/types/component-types.ts +145 -0
  90. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  91. package/scripts/cli/templates/vanilla-templates.js +39 -0
  92. package/scripts/cli/token-manager.js +8 -2
  93. package/scripts/cli/utils/cache-manager.js +240 -0
  94. package/scripts/cli/utils/detector.js +46 -0
  95. package/scripts/cli/utils/diagnostics.js +289 -0
  96. package/scripts/cli/utils/error.js +45 -3
  97. package/scripts/cli/utils/helpers.js +24 -0
  98. package/scripts/cli/utils/logger.js +1 -1
  99. package/scripts/cli/utils/security.js +302 -0
  100. package/scripts/cli/utils/telemetry.js +115 -0
  101. package/scripts/cli/utils/validation.js +4 -38
  102. package/scripts/cli/utils.js +46 -0
  103. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  104. package/src/components/Accordion/Accordion.test.tsx +0 -17
  105. package/src/components/Accordion/Accordion.tsx +0 -4
  106. package/src/components/AtomixGlass/AtomixGlass.tsx +102 -2
  107. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +125 -12
  108. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  109. package/src/components/AtomixGlass/README.md +25 -10
  110. package/src/components/AtomixGlass/animation-system.ts +578 -0
  111. package/src/components/AtomixGlass/shader-utils.ts +4 -1
  112. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  113. package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
  114. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
  115. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
  116. package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
  117. package/src/components/Avatar/Avatar.tsx +1 -1
  118. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  119. package/src/components/Button/Button.stories.tsx +10 -0
  120. package/src/components/Button/Button.test.tsx +16 -11
  121. package/src/components/Button/Button.tsx +4 -4
  122. package/src/components/Card/Card.tsx +1 -1
  123. package/src/components/Dropdown/Dropdown.tsx +12 -12
  124. package/src/components/Form/Select.tsx +62 -3
  125. package/src/components/Modal/Modal.tsx +14 -3
  126. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  127. package/src/components/Slider/Slider.stories.tsx +3 -3
  128. package/src/components/Slider/Slider.tsx +38 -0
  129. package/src/components/Steps/Steps.tsx +3 -3
  130. package/src/components/Tabs/Tabs.tsx +77 -8
  131. package/src/components/Testimonial/Testimonial.tsx +1 -1
  132. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  133. package/src/components/TypedButton/TypedButton.tsx +39 -0
  134. package/src/components/TypedButton/index.ts +2 -0
  135. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  136. package/src/lib/composables/index.ts +4 -7
  137. package/src/lib/composables/types.ts +45 -0
  138. package/src/lib/composables/useAccordion.ts +0 -7
  139. package/src/lib/composables/useAtomixGlass.ts +144 -5
  140. package/src/lib/composables/useChartExport.ts +3 -13
  141. package/src/lib/composables/useDropdown.ts +66 -0
  142. package/src/lib/composables/useFocusTrap.ts +80 -0
  143. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  144. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  145. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  146. package/src/lib/composables/useTooltip.ts +16 -0
  147. package/src/lib/composables/useTypedButton.ts +66 -0
  148. package/src/lib/config/index.ts +62 -5
  149. package/src/lib/constants/components.ts +55 -0
  150. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  151. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  152. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  153. package/src/lib/types/components.ts +37 -11
  154. package/src/lib/types/glass.ts +35 -0
  155. package/src/lib/types/index.ts +1 -0
  156. package/src/lib/utils/displacement-generator.ts +1 -1
  157. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  158. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  159. package/src/styles/06-components/_components.testbutton.scss +212 -0
  160. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  161. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  162. package/src/styles/99-utilities/_index.scss +1 -0
  163. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  164. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  165. package/src/styles/06-components/old.chart.styles.scss +0 -2788
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Atomix CLI Doctor Command
3
+ * Diagnostic tool to verify the environment and project health
4
+ */
5
+
6
+ import { logger } from '../utils/logger.js';
7
+ import { checkRuntimes, checkProjectStructure, checkConfig, checkPermissions, checkPlugins, checkTokens } from '../utils/diagnostics.js';
8
+ import chalk from 'chalk';
9
+
10
+ /** Short descriptions for each doctor check (for --explain) */
11
+ const DOCTOR_CHECK_DESCRIPTIONS = {
12
+ 'Node.js': 'Ensures Node.js >= 18.0.0 for CLI and build compatibility.',
13
+ 'NPM': 'Ensures npm >= 8.0.0 for package management.',
14
+ 'Directory: src': 'Required project directory for application source.',
15
+ 'Directory: scripts/cli': 'Required only for Atomix monorepo development (internal).',
16
+ 'Directory: themes (Recommended)': 'Optional; recommended for custom themes.',
17
+ 'Directory: docs (Recommended)': 'Optional; recommended for documentation.',
18
+ 'Configuration': 'Looks for atomix.config.ts or atomix.config.js in project root.',
19
+ 'Permissions: .': 'Read/write access to project root.',
20
+ 'Permissions: src': 'Read/write access to src directory.',
21
+ 'Plugins': 'Reports plugins registered in atomix.config.',
22
+ 'Tokens': 'Design token discovery: src/styles/01-settings/_settings.*.scss (optional).'
23
+ };
24
+
25
+ /**
26
+ * Action for the `atomix doctor` command
27
+ * @param {object} options - Command options (--explain)
28
+ */
29
+ export async function doctorAction(options = {}) {
30
+ if (options.explain) {
31
+ console.log(chalk.bold.cyan('Atomix doctor checks:\n'));
32
+ for (const [name, desc] of Object.entries(DOCTOR_CHECK_DESCRIPTIONS)) {
33
+ console.log(chalk.bold(name));
34
+ console.log(chalk.gray(` ${desc}\n`));
35
+ }
36
+ console.log(chalk.gray('Run `atomix doctor` (without --explain) to run the checks.'));
37
+ return;
38
+ }
39
+
40
+ const spinner = logger.spinner('Running diagnostics...').start();
41
+
42
+ try {
43
+ const runtimes = await checkRuntimes();
44
+ const structure = await checkProjectStructure();
45
+ const config = await checkConfig();
46
+ const permissions = await checkPermissions();
47
+ const plugins = await checkPlugins();
48
+ const tokens = await checkTokens();
49
+
50
+ spinner.stop();
51
+
52
+ logger.box('Atomix Diagnostic Report', {
53
+ borderColor: 'cyan',
54
+ padding: 1,
55
+ margin: 1
56
+ });
57
+
58
+ const allResults = [...runtimes, ...structure, ...config, ...permissions, ...plugins, ...tokens];
59
+ let issuesFound = false;
60
+
61
+ for (const result of allResults) {
62
+ const icon = result.status === 'pass' ? chalk.green('✓') :
63
+ result.status === 'warn' ? chalk.yellow('!') :
64
+ chalk.red('❌');
65
+
66
+ const statusText = result.status.toUpperCase();
67
+ const nameText = chalk.bold(result.name);
68
+ const messageText = chalk.gray(result.message);
69
+
70
+ console.log(`${icon} [${statusText}] ${nameText}: ${messageText}`);
71
+
72
+ if (result.status !== 'pass' && result.suggestion) {
73
+ issuesFound = true;
74
+ console.log(chalk.blue(` 💡 Suggestion: ${result.suggestion}`));
75
+ }
76
+ }
77
+
78
+ if (!issuesFound) {
79
+ console.log(chalk.bold.green('\n🎉 Your environment is healthy! Everything is ready for Atomix.'));
80
+ } else {
81
+ console.log(chalk.bold.yellow('\n⚠️ Some issues or suggestions were found. Review the report above.'));
82
+ }
83
+
84
+ } catch (error) {
85
+ spinner.fail('Diagnostic failed');
86
+ throw error;
87
+ }
88
+ }
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Atomix CLI Generate Command
3
+ * Orchestrates component generation with validation, hooks, and error handling
3
4
  */
4
5
 
5
6
  import inquirer from 'inquirer';
@@ -8,15 +9,20 @@ import { AtomixCLIError } from '../utils/error.js';
8
9
  import { generator, COMPLEXITY_LEVELS, COMPONENT_FEATURES } from '../internal/generator.js';
9
10
  import { filesystem } from '../internal/filesystem.js';
10
11
  import { validateComponentName } from '../utils/validation.js';
12
+ import { hookManager } from '../internal/hooks.js';
13
+ import { validateComponent } from '../internal/validator.js';
11
14
 
12
15
  /**
13
16
  * Action logic for generating components
17
+ * @param {string} type - Component type (component, token, etc.)
18
+ * @param {string} name - Component name
19
+ * @param {Object} options - CLI options
14
20
  */
15
21
  export async function generateAction(type, name, options) {
16
22
  let config = {
17
23
  name,
18
24
  complexity: options.complexity || 'medium',
19
- features: options.tests ? ['tests', 'storybook', 'styles', 'hook'] : ['storybook', 'styles', 'hook'],
25
+ features: determineFeatures(options),
20
26
  outputPath: options.path || './src/components'
21
27
  };
22
28
 
@@ -25,44 +31,151 @@ export async function generateAction(type, name, options) {
25
31
  if (!config) return;
26
32
  }
27
33
 
34
+ // Pre-generation hook
35
+ try {
36
+ config = await hookManager.trigger('preGenerate', config);
37
+ } catch (error) {
38
+ throw new AtomixCLIError(
39
+ `Pre-generation hook failed: ${error.message}`,
40
+ 'HOOK_EXECUTION_FAILED',
41
+ [
42
+ 'Check preGenerate hook implementation',
43
+ 'Verify hook returns valid configuration object',
44
+ 'Review hook logs with ATOMIX_DEBUG=true'
45
+ ]
46
+ );
47
+ }
48
+
28
49
  const spinner = logger.spinner(`Generating ${type}: ${config.name}...`).start();
29
50
 
30
51
  try {
31
52
  // Validation
32
- const nameValidation = validateComponentName(config.name);
53
+ const nameValidation = await validateComponentName(config.name);
33
54
  if (!nameValidation.isValid) {
34
- throw new AtomixCLIError(nameValidation.error, 'INVALID_NAME', ['Use PascalCase (e.g., MyComponent)']);
55
+ throw new AtomixCLIError(
56
+ nameValidation.error,
57
+ 'INVALID_NAME',
58
+ [
59
+ 'Use PascalCase (e.g., MyComponent, Button)',
60
+ 'Start with a letter (not numbers)',
61
+ 'Avoid special characters except letters and numbers'
62
+ ]
63
+ );
35
64
  }
36
65
 
37
66
  const pathValidation = filesystem.validatePath(config.outputPath);
38
67
  if (!pathValidation.isValid) {
39
- throw new AtomixCLIError(pathValidation.error, 'INVALID_PATH');
68
+ throw new AtomixCLIError(
69
+ pathValidation.error,
70
+ 'INVALID_PATH',
71
+ [
72
+ 'Ensure path is within project root',
73
+ 'Check you have write permissions for target directory',
74
+ 'Use absolute path or path relative to current directory'
75
+ ]
76
+ );
40
77
  }
41
78
 
42
79
  // Execution
43
- const path = await generator.generateComponent(config.name, {
44
- ...config,
45
- logger: { debug: (msg) => logger.debug(msg) }
46
- });
80
+ let path;
81
+ if (options.prompt) {
82
+ path = await generator.generateAIComponent(config.name, options.prompt, {
83
+ ...config,
84
+ logger: { debug: (msg) => logger.debug(msg) }
85
+ });
86
+ } else {
87
+ path = await generator.generateComponent(config.name, {
88
+ ...config,
89
+ logger: { debug: (msg) => logger.debug(msg) }
90
+ });
91
+ }
47
92
 
48
93
  spinner.succeed(`Generated component ${config.name} at ${path}`);
49
94
 
50
95
  if (options.validate) {
51
- const report = await generator.validate(config.name, path);
96
+ let report = await generator.validate(config.name, path);
97
+ // Component-scoped A11y and token validation (Phase 2: design system creator)
98
+ if (type === 'component') {
99
+ const componentReport = await validateComponent(config.name, process.cwd());
100
+ const componentIssues = componentReport.issues.map(
101
+ (i) => (typeof i === 'string' ? i : `[${i.type}] ${i.file}: ${i.message}`)
102
+ );
103
+ report.issues = [...report.issues, ...componentIssues];
104
+ report.valid = report.valid && componentReport.valid;
105
+ }
106
+
107
+ // Validation hook
108
+ try {
109
+ report = await hookManager.trigger('onValidate', report);
110
+ } catch (error) {
111
+ logger.warn(`Validation hook failed: ${error.message}`);
112
+ }
113
+
52
114
  if (!report.valid) {
53
- logger.warn('Validation found minor issues:');
54
- report.issues.forEach(i => logger.info(` - ${i}`));
115
+ logger.warn('Validation found issues:');
116
+ report.issues.forEach((i) => logger.info(` - ${i}`));
55
117
  }
56
118
  }
57
119
 
120
+ // Post-build hook (using generated path as asset)
121
+ try {
122
+ await hookManager.trigger('postBuild', [path]);
123
+ } catch (error) {
124
+ logger.warn(`Post-build hook failed: ${error.message}`);
125
+ }
126
+
58
127
  logger.box(`🎉 Component ${config.name} ready!\nRun: atomix validate component ${config.name}`);
59
128
 
60
129
  } catch (error) {
61
130
  spinner.fail('Generation failed');
131
+
132
+ // Enhance error context for known error types
133
+ if (error.code === 'TEMPLATE_NOT_FOUND') {
134
+ error.suggestions.push('Run `atomix doctor` to check template availability');
135
+ } else if (error.code === 'FRAMEWORK_DETECTION_FAILED') {
136
+ error.suggestions.push('Initialize project with `npm init` or `yarn init`');
137
+ } else if (error.code === 'FILE_WRITE_FAILED') {
138
+ error.suggestions.push('Check disk space and file permissions');
139
+ }
140
+
62
141
  throw error;
63
142
  }
64
143
  }
65
144
 
145
+ /**
146
+ * Determine which features to enable based on CLI options
147
+ * @param {Object} options - CLI options
148
+ * @returns {string[]} Array of feature names
149
+ */
150
+ function determineFeatures(options) {
151
+ const features = [];
152
+
153
+ // Default features (always enabled unless explicitly disabled)
154
+ if (options.storybook !== false) {
155
+ features.push('storybook');
156
+ }
157
+
158
+ if (options.hook !== false) {
159
+ features.push('hook');
160
+ }
161
+
162
+ if (options.styles !== false) {
163
+ features.push('styles');
164
+ }
165
+
166
+ // Optional features (enabled by flag)
167
+ if (options.tests === true) {
168
+ features.push('tests');
169
+ }
170
+
171
+ return features;
172
+ }
173
+
174
+ /**
175
+ * Interactive mode handler
176
+ * Prompts user for component configuration
177
+ * @returns {Promise<Object>} Configuration object
178
+ */
66
179
  async function promptInteractive() {
67
180
  logger.info('🎨 Interactive Component Generator');
68
181
 
@@ -71,20 +184,28 @@ async function promptInteractive() {
71
184
  type: 'input',
72
185
  name: 'name',
73
186
  message: 'Component name (PascalCase):',
74
- validate: (val) => validateComponentName(val).isValid || validateComponentName(val).error
187
+ validate: async (val) => {
188
+ const result = await validateComponentName(val);
189
+ return result.isValid || `Invalid: ${result.error}. Use PascalCase (e.g., MyComponent)`;
190
+ }
75
191
  },
76
192
  {
77
193
  type: 'list',
78
194
  name: 'complexity',
79
195
  message: 'Complexity level:',
80
- choices: Object.keys(COMPLEXITY_LEVELS).map(k => k.toLowerCase())
196
+ choices: Object.keys(COMPLEXITY_LEVELS).map(k => ({
197
+ name: k.toLowerCase(),
198
+ value: k.toLowerCase()
199
+ })),
200
+ default: 'medium'
81
201
  },
82
202
  {
83
203
  type: 'checkbox',
84
204
  name: 'features',
85
205
  message: 'Select features:',
86
206
  choices: Object.keys(COMPONENT_FEATURES).map(k => ({
87
- name: k.toLowerCase(),
207
+ name: `${k.toLowerCase()}${COMPONENT_FEATURES[k].default ? ' (default)' : ''}`,
208
+ value: COMPONENT_FEATURES[k].name,
88
209
  checked: COMPONENT_FEATURES[k].default
89
210
  }))
90
211
  }
@@ -5,40 +5,67 @@
5
5
  import inquirer from 'inquirer';
6
6
  import { logger } from '../utils/logger.js';
7
7
  import { wizard } from '../internal/wizard.js';
8
+ import { isNonInteractive } from '../utils/helpers.js';
9
+ import { AtomixCLIError, ErrorCategory } from '../utils/error.js';
10
+
11
+ const DEFAULT_PROJECT_TYPE = 'react';
12
+ const DEFAULT_FEATURES = ['typescript', 'storybook', 'testing'];
8
13
 
9
14
  /**
10
15
  * Action logic for the init command
16
+ * @param {object} options - Command options (--yes, --type)
11
17
  */
12
- export async function initAction() {
18
+ export async function initAction(options = {}) {
19
+ const useDefaults = options.yes || options.type || isNonInteractive();
20
+ let projectType = (options.type || '').toLowerCase();
21
+ const validTypes = ['react', 'nextjs', 'vanilla'];
22
+ if (options.type && !validTypes.includes(projectType)) {
23
+ throw new AtomixCLIError(
24
+ `Invalid --type: ${options.type}. Use one of: ${validTypes.join(', ')}`,
25
+ ErrorCategory.VALIDATION,
26
+ ['Example: atomix init --type react']
27
+ );
28
+ }
29
+ if (!projectType) projectType = DEFAULT_PROJECT_TYPE;
30
+
13
31
  logger.info('🎨 Atomix Design System Setup Wizard');
14
32
 
15
33
  try {
16
- const answers = await inquirer.prompt([
17
- {
18
- type: 'list',
19
- name: 'projectType',
20
- message: 'What type of project are you building?',
21
- choices: ['react', 'nextjs', 'vanilla']
22
- },
23
- {
24
- type: 'checkbox',
25
- name: 'features',
26
- message: 'Select features:',
27
- choices: ['typescript', 'storybook', 'testing']
28
- }
29
- ]);
34
+ let answers;
35
+ if (useDefaults) {
36
+ answers = {
37
+ projectType,
38
+ features: DEFAULT_FEATURES
39
+ };
40
+ if (options.type) logger.info(`Using project type: ${projectType}`);
41
+ } else {
42
+ answers = await inquirer.prompt([
43
+ {
44
+ type: 'list',
45
+ name: 'projectType',
46
+ message: 'What type of project are you building?',
47
+ choices: ['react', 'nextjs', 'vanilla'],
48
+ default: projectType
49
+ },
50
+ {
51
+ type: 'checkbox',
52
+ name: 'features',
53
+ message: 'Select features:',
54
+ choices: ['typescript', 'storybook', 'testing']
55
+ }
56
+ ]);
57
+ }
30
58
 
31
59
  const spinner = logger.spinner('Setting up project...').start();
32
-
60
+
33
61
  await wizard.initProject(answers.projectType, {
34
62
  ...answers,
35
63
  logger: { debug: (msg) => logger.debug(msg) }
36
64
  });
37
65
 
38
66
  spinner.succeed('Project initialized successfully');
39
-
40
- logger.box('✨ Setup Complete!\nRun: npm run dev');
41
67
 
68
+ logger.box('✨ Setup Complete!\nRun: npm run dev');
42
69
  } catch (error) {
43
70
  logger.error(`Setup failed: ${error.message}`);
44
71
  throw error;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Atomix CLI - Migrate Command
3
+ * Handles migrations from Tailwind, Bootstrap, and other frameworks
4
+ */
5
+
6
+ import { resolve } from 'path';
7
+ import { stat } from 'fs/promises';
8
+ import chalk from 'chalk';
9
+ import { logger } from '../utils/logger.js';
10
+ import { migrateTailwind, migrateBootstrap } from '../migration-tools.js';
11
+ import { AtomixCLIError, ErrorCategory } from '../utils/error.js';
12
+
13
+ /**
14
+ * Ensure source is a directory; throw AtomixCLIError otherwise
15
+ */
16
+ async function ensureSourceIsDirectory(source) {
17
+ const absolute = resolve(process.cwd(), source);
18
+ let st;
19
+ try {
20
+ st = await stat(absolute);
21
+ } catch (err) {
22
+ if (err.code === 'ENOENT') {
23
+ throw new AtomixCLIError(
24
+ `Source not found: ${source}`,
25
+ ErrorCategory.INVALID_PATH,
26
+ ['Source must be a directory. Pass the project root (e.g. . or ./my-app).', 'Check that the path exists.']
27
+ );
28
+ }
29
+ throw err;
30
+ }
31
+ if (!st.isDirectory()) {
32
+ throw new AtomixCLIError(
33
+ `Source is not a directory: ${source}`,
34
+ ErrorCategory.INVALID_PATH,
35
+ ['Source must be the project root directory (e.g. . or ./my-tailwind-app).', 'Do not pass a file path (e.g. package.json).']
36
+ );
37
+ }
38
+ return absolute;
39
+ }
40
+
41
+ /**
42
+ * Migrate action handler
43
+ */
44
+ export async function migrateAction(type, source, options) {
45
+ await ensureSourceIsDirectory(source);
46
+
47
+ logger.info(chalk.blue(`🚀 Starting migration: ${type} from ${source}...`));
48
+
49
+ try {
50
+ let report;
51
+
52
+ switch (type.toLowerCase()) {
53
+ case 'tailwind':
54
+ report = await migrateTailwind(source, options);
55
+ break;
56
+ case 'bootstrap':
57
+ report = await migrateBootstrap(source, options);
58
+ break;
59
+ default:
60
+ throw new AtomixCLIError(
61
+ `Unsupported migration type: ${type}. Use tailwind or bootstrap.`,
62
+ ErrorCategory.VALIDATION,
63
+ ['Example: atomix migrate tailwind .']
64
+ );
65
+ }
66
+
67
+ // Display Migration Report
68
+ displayMigrationReport(report);
69
+
70
+ } catch (error) {
71
+ if (error instanceof AtomixCLIError) throw error;
72
+ throw new AtomixCLIError(
73
+ error.message || 'Migration failed',
74
+ ErrorCategory.FILESYSTEM,
75
+ ['Check source path and permissions. Run with --dry-run to preview.']
76
+ );
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Display migration report in a clean format
82
+ */
83
+ function displayMigrationReport(report) {
84
+ console.log('\n' + chalk.bold.underline('Migration Report'));
85
+ console.log(`${chalk.green('✔')} Files processed: ${report.filesProcessed}`);
86
+ console.log(`${chalk.green('✔')} Classes replaced: ${report.classesReplaced}`);
87
+
88
+ if (report.warnings.length > 0) {
89
+ console.log('\n' + chalk.yellow.bold('Warnings:'));
90
+ const uniqueWarnings = [...new Set(report.warnings.map(w => `${w.file}: ${w.class}`))];
91
+ uniqueWarnings.slice(0, 10).forEach(w => console.log(` ${chalk.yellow('!')} ${w}`));
92
+ if (uniqueWarnings.length > 10) {
93
+ console.log(` ... and ${uniqueWarnings.length - 10} more`);
94
+ }
95
+ }
96
+
97
+ if (report.errors.length > 0) {
98
+ console.log('\n' + chalk.red.bold('Errors:'));
99
+ report.errors.slice(0, 10).forEach(e => console.log(` ${chalk.red('✘')} ${e.file}: ${e.error}`));
100
+ if (report.errors.length > 10) {
101
+ console.log(` ... and ${report.errors.length - 10} more`);
102
+ }
103
+ }
104
+
105
+ console.log('\n' + chalk.green.bold('Migration completed successfully! 🎉'));
106
+ }