@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,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomix CLI Validator Logic
|
|
3
|
+
* Core validation logic for A11y, Tokens, and Performance
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFile, readdir } from 'fs/promises';
|
|
7
|
+
import { glob } from 'glob';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { existsSync, statSync } from 'fs';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Validate Accessibility (A11y)
|
|
13
|
+
* Simple static analysis for common pitfalls
|
|
14
|
+
*/
|
|
15
|
+
export async function validateA11y(projectRoot = process.cwd()) {
|
|
16
|
+
const issues = [];
|
|
17
|
+
const files = await glob('src/**/*.{tsx,jsx,html}', { cwd: projectRoot });
|
|
18
|
+
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
const content = await readFile(join(projectRoot, file), 'utf8');
|
|
21
|
+
|
|
22
|
+
// Check for missing alt on images
|
|
23
|
+
// Skip if alt uses JSX expression syntax like alt={variable} or alt={string}
|
|
24
|
+
const hasAltAttribute = /<img[^>]*\salt=\{[^}]+\}/i.test(content); // JSX expression
|
|
25
|
+
const hasValidAltString = /<img[^>]+alt=["'][^"']+["'][^>]*>/i.test(content); // Valid string alt
|
|
26
|
+
const hasEmptyAltString = /<img[^>]+alt=["']\s*["'][^>]*>/i.test(content); // Empty string alt
|
|
27
|
+
const hasNoAltAttribute = /<img[^>]+(?!alt=)[^>]*>/i.test(content) && !hasAltAttribute;
|
|
28
|
+
|
|
29
|
+
if ((hasNoAltAttribute || hasEmptyAltString) && !(hasAltAttribute || hasValidAltString)) {
|
|
30
|
+
issues.push({
|
|
31
|
+
file,
|
|
32
|
+
type: 'A11y',
|
|
33
|
+
message: 'Missing or empty alt attribute on <img> tag',
|
|
34
|
+
severity: 'error'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check for button without labels (aria-label or text)
|
|
39
|
+
if (/<button[^>]*>\s*<\/button>/i.test(content) && !/aria-label=/i.test(content)) {
|
|
40
|
+
issues.push({
|
|
41
|
+
file,
|
|
42
|
+
type: 'A11y',
|
|
43
|
+
message: 'Button without text content or aria-label',
|
|
44
|
+
severity: 'warn'
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return issues;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Validate Token Usage
|
|
54
|
+
*/
|
|
55
|
+
export async function validateTokens(projectRoot = process.cwd()) {
|
|
56
|
+
const issues = [];
|
|
57
|
+
const themeDir = join(projectRoot, 'src/styles/01-settings');
|
|
58
|
+
|
|
59
|
+
if (!existsSync(themeDir)) {
|
|
60
|
+
issues.push({
|
|
61
|
+
file: 'src/styles/01-settings',
|
|
62
|
+
type: 'Tokens',
|
|
63
|
+
message: 'Design token settings directory missing',
|
|
64
|
+
severity: 'error'
|
|
65
|
+
});
|
|
66
|
+
return issues;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Check for hardcoded colors in SCSS files
|
|
70
|
+
const scssFiles = await glob('src/**/*.scss', { cwd: projectRoot });
|
|
71
|
+
for (const file of scssFiles) {
|
|
72
|
+
const content = await readFile(join(projectRoot, file), 'utf8');
|
|
73
|
+
|
|
74
|
+
// Skip variable definitions (lines with $variable:)
|
|
75
|
+
const lines = content.split('\n');
|
|
76
|
+
const hardcodedColors = [];
|
|
77
|
+
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
// Skip comments
|
|
80
|
+
if (line.trim().startsWith('//') || line.trim().startsWith('/*')) continue;
|
|
81
|
+
|
|
82
|
+
// Skip variable definitions (these SHOULD have hex values)
|
|
83
|
+
if (/^\s*\$[\w-]+:\s*#[\da-fA-F]{3,6}/.test(line)) continue;
|
|
84
|
+
|
|
85
|
+
// Skip CSS var() fallbacks (these are good practices)
|
|
86
|
+
if (/var\([^)]+#[\da-fA-F]{3,6}/.test(line)) continue;
|
|
87
|
+
|
|
88
|
+
// Skip url(), data URIs, and other non-color contexts
|
|
89
|
+
if (/url\(/.test(line)) continue;
|
|
90
|
+
|
|
91
|
+
// Check for actual hardcoded colors in property values
|
|
92
|
+
const hexMatch = line.match(/(?<!\$[\w-]*:\s*)(?<!var\([^)]*)#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})\b(?!;)/g);
|
|
93
|
+
if (hexMatch) {
|
|
94
|
+
hardcodedColors.push(...hexMatch);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (hardcodedColors.length > 0) {
|
|
99
|
+
issues.push({
|
|
100
|
+
file,
|
|
101
|
+
type: 'Tokens',
|
|
102
|
+
message: `Hardcoded hex color(s) found: ${hardcodedColors.join(', ')}. Use variables or tokens.`,
|
|
103
|
+
severity: 'warn'
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return issues;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Validate a single component: structure, A11y, and token usage
|
|
113
|
+
* @param {string} componentName - PascalCase component name (e.g. Button)
|
|
114
|
+
* @param {string} projectRoot - Project root directory
|
|
115
|
+
* @returns {Promise<{ valid: boolean, issues: Array<{type, severity, file, message}>, component: string }>}
|
|
116
|
+
*/
|
|
117
|
+
export async function validateComponent(componentName, projectRoot = process.cwd()) {
|
|
118
|
+
const issues = [];
|
|
119
|
+
const componentsBase = join(projectRoot, 'src/components');
|
|
120
|
+
let componentDir = null;
|
|
121
|
+
|
|
122
|
+
if (!existsSync(componentsBase)) {
|
|
123
|
+
return {
|
|
124
|
+
valid: false,
|
|
125
|
+
issues: [{
|
|
126
|
+
type: 'Structure',
|
|
127
|
+
severity: 'error',
|
|
128
|
+
file: 'src/components',
|
|
129
|
+
message: 'Components directory not found. Expected src/components/<ComponentName>/'
|
|
130
|
+
}],
|
|
131
|
+
component: componentName
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const entries = await readdir(componentsBase, { withFileTypes: true });
|
|
136
|
+
const match = entries.find(
|
|
137
|
+
(e) => e.isDirectory() && e.name.toLowerCase() === componentName.toLowerCase()
|
|
138
|
+
);
|
|
139
|
+
if (!match) {
|
|
140
|
+
return {
|
|
141
|
+
valid: false,
|
|
142
|
+
issues: [{
|
|
143
|
+
type: 'Structure',
|
|
144
|
+
severity: 'error',
|
|
145
|
+
file: `src/components/${componentName}`,
|
|
146
|
+
message: `Component directory not found. Looked in src/components/ for "${componentName}".`
|
|
147
|
+
}],
|
|
148
|
+
component: componentName
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
componentDir = join(componentsBase, match.name);
|
|
152
|
+
const componentFiles = await glob(`${match.name}/**/*.{tsx,jsx,html}`, {
|
|
153
|
+
cwd: componentsBase,
|
|
154
|
+
absolute: false
|
|
155
|
+
});
|
|
156
|
+
const fullPaths = componentFiles.map((f) => join(projectRoot, 'src/components', f));
|
|
157
|
+
|
|
158
|
+
// A11y on component files only
|
|
159
|
+
for (let i = 0; i < fullPaths.length; i++) {
|
|
160
|
+
const file = fullPaths[i];
|
|
161
|
+
const content = await readFile(file, 'utf8');
|
|
162
|
+
const relativeFile = join('src/components', componentFiles[i]);
|
|
163
|
+
// Check for missing alt on images (improved JSX handling)
|
|
164
|
+
const hasAltAttribute = /<img[^>]*\salt=\{[^}]+\}/i.test(content); // JSX expression
|
|
165
|
+
const hasValidAltString = /<img[^>]+alt=["'][^"']+["'][^>]*>/i.test(content); // Valid string alt
|
|
166
|
+
const hasEmptyAltString = /<img[^>]+alt=["']\s*["'][^>]*>/i.test(content); // Empty string alt
|
|
167
|
+
const hasNoAltAttribute = /<img[^>]+(?!alt=)[^>]*>/i.test(content) && !hasAltAttribute;
|
|
168
|
+
|
|
169
|
+
if ((hasNoAltAttribute || hasEmptyAltString) && !(hasAltAttribute || hasValidAltString)) {
|
|
170
|
+
issues.push({
|
|
171
|
+
file: relativeFile,
|
|
172
|
+
type: 'A11y',
|
|
173
|
+
message: 'Missing or empty alt attribute on <img> tag',
|
|
174
|
+
severity: 'error'
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (/<button[^>]*>\s*<\/button>/i.test(content) && !/aria-label=/i.test(content)) {
|
|
178
|
+
issues.push({
|
|
179
|
+
file: relativeFile,
|
|
180
|
+
type: 'A11y',
|
|
181
|
+
message: 'Button without text content or aria-label',
|
|
182
|
+
severity: 'warn'
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Check for hardcoded colors in TSX/JSX component files
|
|
187
|
+
const hexColorRegex = /(?<!['"`])#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})\b(?!['"`])/g;
|
|
188
|
+
const hexMatches = content.match(hexColorRegex);
|
|
189
|
+
if (hexMatches) {
|
|
190
|
+
issues.push({
|
|
191
|
+
file: relativeFile,
|
|
192
|
+
type: 'Tokens',
|
|
193
|
+
message: `Hardcoded hex color(s) found in TSX: ${hexMatches.join(', ')}. Use design tokens or CSS variables.`,
|
|
194
|
+
severity: 'error'
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Token usage: component settings and component SCSS
|
|
200
|
+
const settingsPath = join(projectRoot, 'src/styles/01-settings');
|
|
201
|
+
const compStylesPath = join(projectRoot, 'src/styles/06-components');
|
|
202
|
+
const settingsFile = join(settingsPath, `_settings.${match.name.toLowerCase()}.scss`);
|
|
203
|
+
const compFile = join(compStylesPath, `_components.${match.name.toLowerCase()}.scss`);
|
|
204
|
+
for (const scssPath of [settingsFile, compFile]) {
|
|
205
|
+
if (!existsSync(scssPath)) continue;
|
|
206
|
+
const content = await readFile(scssPath, 'utf8');
|
|
207
|
+
const hexMatch = content.match(/(?<![$/*])#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})\b/g);
|
|
208
|
+
if (hexMatch) {
|
|
209
|
+
issues.push({
|
|
210
|
+
file: scssPath.replace(projectRoot, '').replace(/^\//, '') || scssPath,
|
|
211
|
+
type: 'Tokens',
|
|
212
|
+
message: `Hardcoded hex color(s): ${hexMatch.join(', ')}. Use --atomix-* or project tokens.`,
|
|
213
|
+
severity: 'warn'
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Main component file exists
|
|
219
|
+
const mainExts = ['.tsx', '.jsx'];
|
|
220
|
+
let mainExists = false;
|
|
221
|
+
for (const ext of mainExts) {
|
|
222
|
+
if (existsSync(join(componentDir, `${match.name}${ext}`))) {
|
|
223
|
+
mainExists = true;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (!mainExists) {
|
|
228
|
+
issues.push({
|
|
229
|
+
type: 'Structure',
|
|
230
|
+
severity: 'error',
|
|
231
|
+
file: join('src/components', match.name),
|
|
232
|
+
message: `Main component file not found (e.g. ${match.name}.tsx)`
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
valid: issues.filter((i) => i.severity === 'error').length === 0,
|
|
238
|
+
issues,
|
|
239
|
+
component: match.name
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Validate Performance
|
|
245
|
+
* Calculate bundle size of CSS/JS if dist exists
|
|
246
|
+
*/
|
|
247
|
+
export async function validatePerformance(projectRoot = process.cwd()) {
|
|
248
|
+
const issues = [];
|
|
249
|
+
const distDir = join(projectRoot, 'dist');
|
|
250
|
+
|
|
251
|
+
if (!existsSync(distDir)) {
|
|
252
|
+
return [{
|
|
253
|
+
file: 'dist',
|
|
254
|
+
type: 'Performance',
|
|
255
|
+
message: 'No build artifact found in dist/. Run build first for performance analysis.',
|
|
256
|
+
severity: 'warn'
|
|
257
|
+
}];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const files = await glob('dist/**/*.{js,css}', { cwd: projectRoot });
|
|
261
|
+
for (const file of files) {
|
|
262
|
+
const stats = statSync(join(projectRoot, file));
|
|
263
|
+
const sizeKB = stats.size / 1024;
|
|
264
|
+
|
|
265
|
+
if (sizeKB > 500) { // Arbitrary 500KB threshold
|
|
266
|
+
issues.push({
|
|
267
|
+
file,
|
|
268
|
+
type: 'Performance',
|
|
269
|
+
message: `Bundle size is large: ${sizeKB.toFixed(2)} KB`,
|
|
270
|
+
severity: 'warn'
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return issues;
|
|
276
|
+
}
|
|
@@ -38,13 +38,15 @@ export const wizard = {
|
|
|
38
38
|
// 4. Generate README
|
|
39
39
|
const readme = type === 'react'
|
|
40
40
|
? commonTemplates.readme.react(basename(process.cwd()))
|
|
41
|
-
:
|
|
41
|
+
: type === 'nextjs'
|
|
42
|
+
? commonTemplates.readme.nextjs(basename(process.cwd()))
|
|
43
|
+
: commonTemplates.readme.vanilla(basename(process.cwd()));
|
|
42
44
|
await writeFile('README.md', readme, 'utf8');
|
|
43
45
|
|
|
44
46
|
return true;
|
|
45
47
|
},
|
|
46
48
|
|
|
47
|
-
async _updatePackageJson() {
|
|
49
|
+
async _updatePackageJson(type, template, options = {}) {
|
|
48
50
|
const packageJsonPath = join(process.cwd(), 'package.json');
|
|
49
51
|
let pkg = { scripts: {}, dependencies: {}, devDependencies: {} };
|
|
50
52
|
|
|
@@ -52,10 +54,62 @@ export const wizard = {
|
|
|
52
54
|
pkg = JSON.parse(await readFile(packageJsonPath, 'utf8'));
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
// Merge logic
|
|
56
|
-
|
|
57
|
-
pkg.scripts['build:theme'] =
|
|
58
|
-
|
|
57
|
+
// Merge logic: ensure Atomix CLI scripts exist for scaffolded projects
|
|
58
|
+
pkg.scripts = pkg.scripts || {};
|
|
59
|
+
pkg.scripts['build:theme'] = pkg.scripts['build:theme'] || 'atomix build-theme themes/custom';
|
|
60
|
+
pkg.scripts['generate:component'] = pkg.scripts['generate:component'] || 'atomix generate component';
|
|
61
|
+
pkg.scripts['validate'] = pkg.scripts['validate'] || 'atomix validate';
|
|
62
|
+
|
|
63
|
+
// Add required peer dependencies according to project guidelines
|
|
64
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
65
|
+
pkg.devDependencies = pkg.devDependencies || {};
|
|
66
|
+
|
|
67
|
+
// Required runtime dependencies (from CLI_PEER_DEPENDENCIES.md)
|
|
68
|
+
if (!pkg.dependencies.react) {
|
|
69
|
+
pkg.dependencies.react = '^18.0.0';
|
|
70
|
+
}
|
|
71
|
+
if (!pkg.dependencies['react-dom']) {
|
|
72
|
+
pkg.dependencies['react-dom'] = '^18.0.0';
|
|
73
|
+
}
|
|
74
|
+
if (!pkg.dependencies['@phosphor-icons/react']) {
|
|
75
|
+
pkg.dependencies['@phosphor-icons/react'] = '2.1.10';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Add @shohojdhara/atomix as dependency
|
|
79
|
+
if (!pkg.dependencies['@shohojdhara/atomix']) {
|
|
80
|
+
pkg.dependencies['@shohojdhara/atomix'] = 'latest';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Required devDependencies based on template
|
|
84
|
+
if (template.devDependencies && Array.isArray(template.devDependencies)) {
|
|
85
|
+
// Template defines an array of package names (without versions)
|
|
86
|
+
for (const dep of template.devDependencies) {
|
|
87
|
+
if (!pkg.devDependencies[dep]) {
|
|
88
|
+
// Use default versions for common packages
|
|
89
|
+
const defaultVersions = {
|
|
90
|
+
'vite': '^4.0.0',
|
|
91
|
+
'@vitejs/plugin-react': '^4.0.0',
|
|
92
|
+
'typescript': '^5.0.0',
|
|
93
|
+
'@types/react': '^18.0.0',
|
|
94
|
+
'@types/react-dom': '^18.0.0',
|
|
95
|
+
'sass': '^1.69.0',
|
|
96
|
+
'@types/node': '^20.0.0',
|
|
97
|
+
'eslint': '^8.0.0',
|
|
98
|
+
'eslint-config-next': '^14.0.0'
|
|
99
|
+
};
|
|
100
|
+
pkg.devDependencies[dep] = defaultVersions[dep] || '^1.0.0';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Add engines field for Node.js version requirement
|
|
106
|
+
if (!pkg.engines) {
|
|
107
|
+
pkg.engines = {
|
|
108
|
+
node: '>=18.0.0',
|
|
109
|
+
npm: '>=8.0.0'
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
59
113
|
await writeFile(packageJsonPath, JSON.stringify(pkg, null, 2), 'utf8');
|
|
60
114
|
}
|
|
61
115
|
};
|
package/scripts/cli/mappings.js
CHANGED
|
@@ -65,6 +65,29 @@ export const tailwindToAtomix = {
|
|
|
65
65
|
'rounded-md': 'u-radius-md',
|
|
66
66
|
'rounded-lg': 'u-radius-lg',
|
|
67
67
|
'rounded-full': 'u-radius-full',
|
|
68
|
+
// Shadow
|
|
69
|
+
'shadow-sm': 'u-shadow-sm',
|
|
70
|
+
'shadow': 'u-shadow-md',
|
|
71
|
+
'shadow-md': 'u-shadow-md',
|
|
72
|
+
'shadow-lg': 'u-shadow-lg',
|
|
73
|
+
'shadow-xl': 'u-shadow-xl',
|
|
74
|
+
'shadow-2xl': 'u-shadow-2xl',
|
|
75
|
+
'shadow-inner': 'u-shadow-inner',
|
|
76
|
+
'shadow-none': 'u-shadow-none',
|
|
77
|
+
// Opacity
|
|
78
|
+
'opacity-0': 'u-opacity-0',
|
|
79
|
+
'opacity-25': 'u-opacity-25',
|
|
80
|
+
'opacity-50': 'u-opacity-50',
|
|
81
|
+
'opacity-75': 'u-opacity-75',
|
|
82
|
+
'opacity-100': 'u-opacity-100',
|
|
83
|
+
// Z-index
|
|
84
|
+
'z-0': 'u-z-0',
|
|
85
|
+
'z-10': 'u-z-10',
|
|
86
|
+
'z-20': 'u-z-20',
|
|
87
|
+
'z-30': 'u-z-30',
|
|
88
|
+
'z-40': 'u-z-40',
|
|
89
|
+
'z-50': 'u-z-50',
|
|
90
|
+
'z-auto': 'u-z-auto',
|
|
68
91
|
};
|
|
69
92
|
|
|
70
93
|
/**
|