@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,109 @@
1
+ /**
2
+ * Atomix CLI Clean Command
3
+ * Safely clean build artifacts and cache files
4
+ */
5
+
6
+ import { logger } from '../utils/logger.js';
7
+ import { AtomixCLIError } from '../utils/error.js';
8
+ import { cacheManager } from '../utils/cache-manager.js';
9
+
10
+ /**
11
+ * Action logic for cleaning build artifacts
12
+ * @param {object} options - Command options
13
+ * @param {boolean} options.all - Clean node_modules as well
14
+ * @param {boolean} options.cache - Only clean cache directories
15
+ * @param {boolean} options.dryRun - Preview without deleting
16
+ * @param {boolean} options.verbose - Show detailed output
17
+ */
18
+ export async function cleanAction(options) {
19
+ const spinner = logger.spinner('Analyzing project...').start();
20
+
21
+ try {
22
+ // Step 1: Identify what can be cleaned
23
+ spinner.text = 'Scanning for cleanable files...';
24
+ const targets = await cacheManager.identifyTargets(options);
25
+
26
+ // Filter out protected files
27
+ const safeTargets = targets.filter(target => {
28
+ if (cacheManager.isProtected(target.path)) {
29
+ logger.debug(`Skipping protected file: ${target.path}`);
30
+ return false;
31
+ }
32
+ return true;
33
+ });
34
+
35
+ // Step 2: Handle empty state
36
+ if (safeTargets.length === 0) {
37
+ spinner.succeed('Nothing to clean! Your project is already tidy.');
38
+ return;
39
+ }
40
+
41
+ // Step 3: Calculate total size
42
+ const totalSize = await cacheManager.calculateSize(safeTargets);
43
+ const formattedSize = cacheManager.formatBytes(totalSize);
44
+
45
+ // Step 4: Handle dry-run mode
46
+ if (options.dryRun || process.env.ATOMIX_DRY_RUN === 'true') {
47
+ spinner.stop();
48
+ cacheManager.displayDryRun(safeTargets);
49
+ logger.info(
50
+ `\nℹ️ Total size: ${formattedSize}\n` +
51
+ `⚠️ Run without --dry-run to actually delete these files.`
52
+ );
53
+ return;
54
+ }
55
+
56
+ // Step 5: Perform cleanup
57
+ spinner.text = `Cleaning ${safeTargets.length} item(s)...`;
58
+
59
+ let successCount = 0;
60
+ let errorCount = 0;
61
+ const errors = [];
62
+
63
+ for (const target of safeTargets) {
64
+ try {
65
+ if (options.verbose) {
66
+ logger.info(`Removing: ${target.relativePath}`);
67
+ }
68
+
69
+ await cacheManager.deletePath(target.path, options);
70
+ successCount++;
71
+ } catch (error) {
72
+ errorCount++;
73
+ errors.push({
74
+ path: target.relativePath,
75
+ error: error.message
76
+ });
77
+ logger.debug(`Failed to delete ${target.path}: ${error.message}`);
78
+ }
79
+ }
80
+
81
+ // Step 6: Report results
82
+ if (errorCount > 0) {
83
+ spinner.warn(`Cleanup completed with ${errorCount} warning(s)`);
84
+
85
+ if (options.verbose && errors.length > 0) {
86
+ logger.warn('\nWarnings:');
87
+ errors.forEach(err => {
88
+ logger.warn(` • ${err.path}: ${err.error}`);
89
+ });
90
+ }
91
+ } else {
92
+ spinner.succeed(`Cleanup completed! Removed ${successCount} item(s) (${formattedSize})`);
93
+ }
94
+
95
+ } catch (error) {
96
+ spinner.fail('Cleanup failed');
97
+
98
+ // Re-throw as AtomixCLIError with helpful suggestions
99
+ throw new AtomixCLIError(
100
+ error.message,
101
+ 'FILESYSTEM_ERROR',
102
+ [
103
+ 'Check if you have write permissions for the target directories',
104
+ 'Ensure no files are locked by another process',
105
+ 'Try running with --verbose to see which file caused the issue'
106
+ ]
107
+ );
108
+ }
109
+ }
@@ -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
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Atomix CLI Generate Command
3
+ * Orchestrates component generation with validation, hooks, and error handling
4
+ */
5
+
6
+ import inquirer from 'inquirer';
7
+ import { logger } from '../utils/logger.js';
8
+ import { AtomixCLIError } from '../utils/error.js';
9
+ import { generator, COMPLEXITY_LEVELS, COMPONENT_FEATURES } from '../internal/generator.js';
10
+ import { filesystem } from '../internal/filesystem.js';
11
+ import { validateComponentName } from '../utils/validation.js';
12
+ import { hookManager } from '../internal/hooks.js';
13
+ import { validateComponent } from '../internal/validator.js';
14
+
15
+ /**
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
20
+ */
21
+ export async function generateAction(type, name, options) {
22
+ let config = {
23
+ name,
24
+ complexity: options.complexity || 'medium',
25
+ features: determineFeatures(options),
26
+ outputPath: options.path || './src/components'
27
+ };
28
+
29
+ if (options.interactive) {
30
+ config = await promptInteractive();
31
+ if (!config) return;
32
+ }
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
+
49
+ const spinner = logger.spinner(`Generating ${type}: ${config.name}...`).start();
50
+
51
+ try {
52
+ // Validation
53
+ const nameValidation = await validateComponentName(config.name);
54
+ if (!nameValidation.isValid) {
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
+ );
64
+ }
65
+
66
+ const pathValidation = filesystem.validatePath(config.outputPath);
67
+ if (!pathValidation.isValid) {
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
+ );
77
+ }
78
+
79
+ // Execution
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
+ }
92
+
93
+ spinner.succeed(`Generated component ${config.name} at ${path}`);
94
+
95
+ if (options.validate) {
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
+
114
+ if (!report.valid) {
115
+ logger.warn('Validation found issues:');
116
+ report.issues.forEach((i) => logger.info(` - ${i}`));
117
+ }
118
+ }
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
+
127
+ logger.box(`🎉 Component ${config.name} ready!\nRun: atomix validate component ${config.name}`);
128
+
129
+ } catch (error) {
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
+
141
+ throw error;
142
+ }
143
+ }
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
+ */
179
+ async function promptInteractive() {
180
+ logger.info('🎨 Interactive Component Generator');
181
+
182
+ const answers = await inquirer.prompt([
183
+ {
184
+ type: 'input',
185
+ name: 'name',
186
+ message: 'Component name (PascalCase):',
187
+ validate: async (val) => {
188
+ const result = await validateComponentName(val);
189
+ return result.isValid || `Invalid: ${result.error}. Use PascalCase (e.g., MyComponent)`;
190
+ }
191
+ },
192
+ {
193
+ type: 'list',
194
+ name: 'complexity',
195
+ message: 'Complexity level:',
196
+ choices: Object.keys(COMPLEXITY_LEVELS).map(k => ({
197
+ name: k.toLowerCase(),
198
+ value: k.toLowerCase()
199
+ })),
200
+ default: 'medium'
201
+ },
202
+ {
203
+ type: 'checkbox',
204
+ name: 'features',
205
+ message: 'Select features:',
206
+ choices: Object.keys(COMPONENT_FEATURES).map(k => ({
207
+ name: `${k.toLowerCase()}${COMPONENT_FEATURES[k].default ? ' (default)' : ''}`,
208
+ value: COMPONENT_FEATURES[k].name,
209
+ checked: COMPONENT_FEATURES[k].default
210
+ }))
211
+ }
212
+ ]);
213
+
214
+ return {
215
+ ...answers,
216
+ outputPath: './src/components'
217
+ };
218
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Atomix CLI Init Command
3
+ */
4
+
5
+ import inquirer from 'inquirer';
6
+ import { logger } from '../utils/logger.js';
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'];
13
+
14
+ /**
15
+ * Action logic for the init command
16
+ * @param {object} options - Command options (--yes, --type)
17
+ */
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
+
31
+ logger.info('🎨 Atomix Design System Setup Wizard');
32
+
33
+ try {
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
+ }
58
+
59
+ const spinner = logger.spinner('Setting up project...').start();
60
+
61
+ await wizard.initProject(answers.projectType, {
62
+ ...answers,
63
+ logger: { debug: (msg) => logger.debug(msg) }
64
+ });
65
+
66
+ spinner.succeed('Project initialized successfully');
67
+
68
+ logger.box('✨ Setup Complete!\nRun: npm run dev');
69
+ } catch (error) {
70
+ logger.error(`Setup failed: ${error.message}`);
71
+ throw error;
72
+ }
73
+ }
@@ -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
+ }