@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.
- package/atomix.config.ts +58 -1
- package/dist/atomix.css +148 -120
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +33 -0
- package/dist/charts.js +1227 -122
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +33 -10
- package/dist/core.js +1052 -41
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +33 -0
- package/dist/forms.js +2086 -1035
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +42 -1
- package/dist/heavy.js +1620 -600
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +441 -270
- package/dist/index.esm.js +1900 -638
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1935 -670
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +6 -3
- package/scripts/atomix-cli.js +148 -4
- package/scripts/cli/__tests__/basic.test.js +3 -2
- package/scripts/cli/__tests__/clean.test.js +278 -0
- package/scripts/cli/__tests__/component-validator.test.js +433 -0
- package/scripts/cli/__tests__/generator.test.js +613 -0
- package/scripts/cli/__tests__/glass-motion.test.js +256 -0
- package/scripts/cli/__tests__/integration.test.js +719 -108
- package/scripts/cli/__tests__/migrate.test.js +74 -0
- package/scripts/cli/__tests__/security.test.js +206 -0
- package/scripts/cli/__tests__/test-setup.js +3 -1
- package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
- package/scripts/cli/__tests__/token-provider.test.js +361 -0
- package/scripts/cli/__tests__/utils.test.js +5 -5
- package/scripts/cli/commands/benchmark.js +105 -0
- package/scripts/cli/commands/build-theme.js +4 -1
- package/scripts/cli/commands/clean.js +109 -0
- package/scripts/cli/commands/doctor.js +88 -0
- package/scripts/cli/commands/generate.js +135 -14
- package/scripts/cli/commands/init.js +45 -18
- package/scripts/cli/commands/migrate.js +106 -0
- package/scripts/cli/commands/sync-tokens.js +206 -0
- package/scripts/cli/commands/theme-bridge.js +248 -0
- package/scripts/cli/commands/tokens.js +157 -0
- package/scripts/cli/commands/validate.js +194 -0
- package/scripts/cli/internal/ai-engine.js +156 -0
- package/scripts/cli/internal/component-validator.js +443 -0
- package/scripts/cli/internal/config-loader.js +162 -0
- package/scripts/cli/internal/filesystem.js +102 -2
- package/scripts/cli/internal/generator.js +359 -39
- package/scripts/cli/internal/glass-generator.js +398 -0
- package/scripts/cli/internal/hook-generator.js +369 -0
- package/scripts/cli/internal/hooks.js +61 -0
- package/scripts/cli/internal/itcss-generator.js +565 -0
- package/scripts/cli/internal/motion-generator.js +679 -0
- package/scripts/cli/internal/template-engine.js +301 -0
- package/scripts/cli/internal/theme-bridge.js +664 -0
- package/scripts/cli/internal/tokens/engine.js +122 -0
- package/scripts/cli/internal/tokens/provider.js +34 -0
- package/scripts/cli/internal/tokens/providers/figma.js +50 -0
- package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
- package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
- package/scripts/cli/internal/tokens/token-provider.js +443 -0
- package/scripts/cli/internal/tokens/token-validator.js +513 -0
- package/scripts/cli/internal/validator.js +276 -0
- package/scripts/cli/internal/wizard.js +60 -6
- package/scripts/cli/mappings.js +23 -0
- package/scripts/cli/migration-tools.js +164 -94
- package/scripts/cli/plugins/style-dictionary.js +46 -0
- package/scripts/cli/templates/README.md +525 -95
- package/scripts/cli/templates/common-templates.js +40 -14
- package/scripts/cli/templates/components/react-component.ts +282 -0
- package/scripts/cli/templates/config/project-config.ts +112 -0
- package/scripts/cli/templates/hooks/use-component.ts +477 -0
- package/scripts/cli/templates/index.js +19 -4
- package/scripts/cli/templates/index.ts +171 -0
- package/scripts/cli/templates/next-templates.js +72 -0
- package/scripts/cli/templates/react-templates.js +70 -126
- package/scripts/cli/templates/scss-templates.js +35 -35
- package/scripts/cli/templates/stories/storybook-story.ts +241 -0
- package/scripts/cli/templates/styles/scss-component.ts +255 -0
- package/scripts/cli/templates/tests/vitest-test.ts +229 -0
- package/scripts/cli/templates/token-templates.js +337 -1
- package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
- package/scripts/cli/templates/types/component-types.ts +145 -0
- package/scripts/cli/templates/utils/testing-utils.ts +144 -0
- package/scripts/cli/templates/vanilla-templates.js +39 -0
- package/scripts/cli/token-manager.js +8 -2
- package/scripts/cli/utils/cache-manager.js +240 -0
- package/scripts/cli/utils/detector.js +46 -0
- package/scripts/cli/utils/diagnostics.js +289 -0
- package/scripts/cli/utils/error.js +45 -3
- package/scripts/cli/utils/helpers.js +24 -0
- package/scripts/cli/utils/logger.js +1 -1
- package/scripts/cli/utils/security.js +302 -0
- package/scripts/cli/utils/telemetry.js +115 -0
- package/scripts/cli/utils/validation.js +4 -38
- package/scripts/cli/utils.js +46 -0
- package/src/components/Accordion/Accordion.stories.tsx +0 -18
- package/src/components/Accordion/Accordion.test.tsx +0 -17
- package/src/components/Accordion/Accordion.tsx +0 -4
- package/src/components/AtomixGlass/AtomixGlass.tsx +102 -2
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +125 -12
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
- package/src/components/AtomixGlass/README.md +25 -10
- package/src/components/AtomixGlass/animation-system.ts +578 -0
- package/src/components/AtomixGlass/shader-utils.ts +4 -1
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
- package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
- package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
- package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
- package/src/components/Button/Button.stories.tsx +10 -0
- package/src/components/Button/Button.test.tsx +16 -11
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Dropdown/Dropdown.tsx +12 -12
- package/src/components/Form/Select.tsx +62 -3
- package/src/components/Modal/Modal.tsx +14 -3
- package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
- package/src/components/Slider/Slider.stories.tsx +3 -3
- package/src/components/Slider/Slider.tsx +38 -0
- package/src/components/Steps/Steps.tsx +3 -3
- package/src/components/Tabs/Tabs.tsx +77 -8
- package/src/components/Testimonial/Testimonial.tsx +1 -1
- package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
- package/src/components/TypedButton/TypedButton.tsx +39 -0
- package/src/components/TypedButton/index.ts +2 -0
- package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
- package/src/lib/composables/index.ts +4 -7
- package/src/lib/composables/types.ts +45 -0
- package/src/lib/composables/useAccordion.ts +0 -7
- package/src/lib/composables/useAtomixGlass.ts +144 -5
- package/src/lib/composables/useChartExport.ts +3 -13
- package/src/lib/composables/useDropdown.ts +66 -0
- package/src/lib/composables/useFocusTrap.ts +80 -0
- package/src/lib/composables/usePerformanceMonitor.ts +448 -0
- package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
- package/src/lib/composables/useResponsiveGlass.ts +441 -0
- package/src/lib/composables/useTooltip.ts +16 -0
- package/src/lib/composables/useTypedButton.ts +66 -0
- package/src/lib/config/index.ts +62 -5
- package/src/lib/constants/components.ts +55 -0
- package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
- package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
- package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
- package/src/lib/types/components.ts +37 -11
- package/src/lib/types/glass.ts +35 -0
- package/src/lib/types/index.ts +1 -0
- package/src/lib/utils/displacement-generator.ts +1 -1
- package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
- package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
- package/src/styles/06-components/_components.testbutton.scss +212 -0
- package/src/styles/06-components/_components.testtypecheck.scss +212 -0
- package/src/styles/06-components/_components.typedbutton.scss +212 -0
- package/src/styles/99-utilities/_index.scss +1 -0
- package/src/styles/99-utilities/_utilities.text.scss +1 -1
- package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
- 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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
|
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) =>
|
|
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 =>
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
+
}
|