@shohojdhara/atomix 0.3.14 → 0.3.15

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 (173) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/build-tools/EXAMPLES.md +372 -0
  3. package/build-tools/README.md +242 -0
  4. package/build-tools/__tests__/error-handler.test.js +230 -0
  5. package/build-tools/__tests__/index.test.js +141 -0
  6. package/build-tools/__tests__/rollup-plugin.test.js +194 -0
  7. package/build-tools/__tests__/utils.test.js +161 -0
  8. package/build-tools/__tests__/vite-plugin.test.js +129 -0
  9. package/build-tools/__tests__/webpack-loader.test.js +190 -0
  10. package/build-tools/error-handler.js +308 -0
  11. package/build-tools/index.d.ts +43 -0
  12. package/build-tools/index.js +88 -0
  13. package/build-tools/package.json +67 -0
  14. package/build-tools/rollup-plugin.js +236 -0
  15. package/build-tools/types.d.ts +163 -0
  16. package/build-tools/utils.js +203 -0
  17. package/build-tools/vite-plugin.js +161 -0
  18. package/build-tools/webpack-loader.js +123 -0
  19. package/dist/atomix.css +203 -90
  20. package/dist/atomix.css.map +1 -1
  21. package/dist/atomix.min.css +3 -3
  22. package/dist/atomix.min.css.map +1 -1
  23. package/dist/build-tools/EXAMPLES.md +372 -0
  24. package/dist/build-tools/README.md +242 -0
  25. package/dist/build-tools/__tests__/error-handler.test.js +230 -0
  26. package/dist/build-tools/__tests__/index.test.js +141 -0
  27. package/dist/build-tools/__tests__/rollup-plugin.test.js +194 -0
  28. package/dist/build-tools/__tests__/utils.test.js +161 -0
  29. package/dist/build-tools/__tests__/vite-plugin.test.js +129 -0
  30. package/dist/build-tools/__tests__/webpack-loader.test.js +190 -0
  31. package/dist/build-tools/error-handler.js +308 -0
  32. package/dist/build-tools/index.d.ts +43 -0
  33. package/dist/build-tools/index.js +88 -0
  34. package/dist/build-tools/package.json +67 -0
  35. package/dist/build-tools/rollup-plugin.js +236 -0
  36. package/dist/build-tools/types.d.ts +163 -0
  37. package/dist/build-tools/utils.js +203 -0
  38. package/dist/build-tools/vite-plugin.js +161 -0
  39. package/dist/build-tools/webpack-loader.js +123 -0
  40. package/dist/charts.d.ts +1 -1
  41. package/dist/charts.js +86 -57
  42. package/dist/charts.js.map +1 -1
  43. package/dist/core.d.ts +1 -1
  44. package/dist/core.js +136 -112
  45. package/dist/core.js.map +1 -1
  46. package/dist/forms.d.ts +2 -5
  47. package/dist/forms.js +140 -128
  48. package/dist/forms.js.map +1 -1
  49. package/dist/heavy.d.ts +1 -1
  50. package/dist/heavy.js +136 -112
  51. package/dist/heavy.js.map +1 -1
  52. package/dist/index.d.ts +9 -61
  53. package/dist/index.esm.js +237 -286
  54. package/dist/index.esm.js.map +1 -1
  55. package/dist/index.js +250 -299
  56. package/dist/index.js.map +1 -1
  57. package/dist/index.min.js +1 -1
  58. package/dist/index.min.js.map +1 -1
  59. package/package.json +23 -8
  60. package/scripts/atomix-cli.js +170 -73
  61. package/scripts/cli/__tests__/README.md +81 -0
  62. package/scripts/cli/__tests__/basic.test.js +115 -0
  63. package/scripts/cli/__tests__/component-generator.test.js +332 -0
  64. package/scripts/cli/__tests__/integration.test.js +327 -0
  65. package/scripts/cli/__tests__/test-setup.js +133 -0
  66. package/scripts/cli/__tests__/token-manager.test.js +251 -0
  67. package/scripts/cli/__tests__/utils.test.js +161 -0
  68. package/scripts/cli/component-generator.js +253 -299
  69. package/scripts/cli/dependency-checker.js +355 -0
  70. package/scripts/cli/interactive-init.js +46 -5
  71. package/scripts/cli/template-manager.js +0 -2
  72. package/scripts/cli/templates/common-templates.js +636 -0
  73. package/scripts/cli/templates/composable-templates.js +148 -126
  74. package/scripts/cli/templates/index.js +23 -16
  75. package/scripts/cli/templates/project-templates.js +151 -23
  76. package/scripts/cli/templates/react-templates.js +280 -210
  77. package/scripts/cli/templates/scss-templates.js +90 -91
  78. package/scripts/cli/templates/testing-templates.js +206 -27
  79. package/scripts/cli/templates/testing-utils.js +278 -0
  80. package/scripts/cli/templates/types-templates.js +70 -56
  81. package/scripts/cli/theme-bridge.js +8 -2
  82. package/scripts/cli/token-manager.js +318 -206
  83. package/scripts/cli/utils.js +0 -1
  84. package/src/components/Accordion/Accordion.stories.tsx +369 -870
  85. package/src/components/AtomixGlass/AtomixGlass.tsx +80 -39
  86. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +103 -81
  87. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +8 -7
  88. package/src/components/AtomixGlass/glass-utils.ts +2 -2
  89. package/src/components/AtomixGlass/shader-utils.ts +5 -0
  90. package/src/components/AtomixGlass/stories/Customization.stories.tsx +131 -0
  91. package/src/components/AtomixGlass/stories/Examples.stories.tsx +2957 -2853
  92. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -1
  93. package/src/components/AtomixGlass/stories/Overview.stories.tsx +348 -0
  94. package/src/components/AtomixGlass/stories/Performance.stories.tsx +103 -0
  95. package/src/components/AtomixGlass/stories/Playground.stories.tsx +50 -35
  96. package/src/components/AtomixGlass/stories/{ShaderVariants.stories.tsx → Shaders.stories.tsx} +1 -1
  97. package/src/components/AtomixGlass/stories/shared-components.tsx +90 -190
  98. package/src/components/Avatar/Avatar.stories.tsx +213 -1
  99. package/src/components/Badge/Badge.stories.tsx +121 -362
  100. package/src/components/Block/Block.stories.tsx +21 -12
  101. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +141 -23
  102. package/src/components/Button/Button.stories.tsx +463 -1126
  103. package/src/components/Button/Button.test.tsx +107 -0
  104. package/src/components/Button/Button.tsx +46 -50
  105. package/src/components/Button/ButtonGroup.stories.tsx +373 -217
  106. package/src/components/Callout/Callout.stories.tsx +289 -634
  107. package/src/components/Card/Card.stories.tsx +248 -68
  108. package/src/components/Chart/Chart.stories.tsx +150 -8
  109. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +151 -69
  110. package/src/components/Countdown/Countdown.stories.tsx +115 -8
  111. package/src/components/DataTable/DataTable.stories.tsx +346 -146
  112. package/src/components/DatePicker/DatePicker.stories.tsx +325 -1066
  113. package/src/components/Dropdown/Dropdown.stories.tsx +153 -33
  114. package/src/components/EdgePanel/EdgePanel.stories.tsx +230 -21
  115. package/src/components/Footer/Footer.stories.tsx +392 -328
  116. package/src/components/Form/Checkbox.stories.tsx +140 -6
  117. package/src/components/Form/Checkbox.test.tsx +63 -0
  118. package/src/components/Form/Checkbox.tsx +87 -51
  119. package/src/components/Form/Form.stories.tsx +119 -20
  120. package/src/components/Form/FormGroup.stories.tsx +127 -4
  121. package/src/components/Form/Radio.stories.tsx +140 -5
  122. package/src/components/Form/Select.stories.tsx +140 -8
  123. package/src/components/Form/Textarea.stories.tsx +149 -6
  124. package/src/components/Hero/Hero.stories.tsx +333 -32
  125. package/src/components/List/List.stories.tsx +141 -3
  126. package/src/components/Modal/Modal.stories.tsx +181 -42
  127. package/src/components/Popover/Popover.stories.tsx +448 -98
  128. package/src/components/Progress/Progress.stories.tsx +167 -5
  129. package/src/components/River/River.stories.tsx +1 -1
  130. package/src/components/SectionIntro/SectionIntro.stories.tsx +240 -48
  131. package/src/components/Spinner/Spinner.stories.tsx +102 -8
  132. package/src/components/Steps/Steps.stories.tsx +172 -43
  133. package/src/components/Tabs/Tabs.stories.tsx +136 -10
  134. package/src/components/Testimonial/Testimonial.stories.tsx +120 -3
  135. package/src/components/Todo/Todo.stories.tsx +198 -9
  136. package/src/components/Toggle/Toggle.stories.tsx +126 -39
  137. package/src/components/Tooltip/Tooltip.stories.tsx +194 -104
  138. package/src/components/Upload/Upload.stories.tsx +113 -24
  139. package/src/lib/README.md +2 -2
  140. package/src/lib/__tests__/theme-tools.test.ts +193 -0
  141. package/src/lib/composables/index.ts +2 -2
  142. package/src/lib/composables/useAtomixGlass.ts +28 -56
  143. package/src/lib/composables/useChartExport.ts +2 -7
  144. package/src/lib/composables/useDataTable.ts +46 -29
  145. package/src/lib/constants/components.ts +9 -32
  146. package/src/lib/theme/devtools/CLI.ts +1 -1
  147. package/src/lib/types/components.ts +1 -1
  148. package/src/lib/utils/__tests__/csv.test.ts +45 -0
  149. package/src/lib/utils/csv.ts +17 -0
  150. package/src/lib/utils/dataTableExport.ts +1 -10
  151. package/src/styles/01-settings/_index.scss +2 -1
  152. package/src/styles/01-settings/_settings.accordion.scss +28 -7
  153. package/src/styles/01-settings/_settings.colors.scss +11 -11
  154. package/src/styles/01-settings/_settings.typography.scss +5 -5
  155. package/src/styles/02-tools/_tools.utility-api.scss +14 -0
  156. package/src/styles/06-components/_components.accordion.scss +56 -14
  157. package/src/styles/06-components/_components.checkbox.scss +23 -17
  158. package/src/styles/99-utilities/_index.scss +2 -0
  159. package/src/styles/99-utilities/_utilities.scss +3 -1
  160. package/src/styles/99-utilities/_utilities.text-gradient.scss +45 -0
  161. package/themes/dark-complementary/README.md +98 -0
  162. package/themes/dark-complementary/index.scss +158 -0
  163. package/themes/default-light/README.md +81 -0
  164. package/themes/default-light/index.scss +154 -0
  165. package/themes/high-contrast/README.md +105 -0
  166. package/themes/high-contrast/index.scss +172 -0
  167. package/themes/test-theme/README.md +38 -0
  168. package/themes/test-theme/index.scss +47 -0
  169. package/scripts/cli/templates-original-backup.js +0 -1655
  170. package/scripts/cli/templates_backup.js +0 -684
  171. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +0 -1438
  172. package/src/lib/composables/useButton.ts +0 -93
  173. package/src/lib/composables/useCheckbox.ts +0 -70
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shohojdhara/atomix",
3
- "version": "0.3.14",
3
+ "version": "0.3.15",
4
4
  "description": "Atomix Design System - A modern component library for web applications",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -111,6 +111,12 @@
111
111
  "import": "./dist/heavy.js",
112
112
  "default": "./dist/heavy.js"
113
113
  },
114
+ "./build-tools": {
115
+ "types": "./build-tools/index.d.ts",
116
+ "import": "./build-tools/index.js",
117
+ "require": "./build-tools/index.js",
118
+ "default": "./build-tools/index.js"
119
+ },
114
120
  "./package.json": "./package.json"
115
121
  },
116
122
  "dependencies": {
@@ -128,6 +134,8 @@
128
134
  },
129
135
  "devDependencies": {
130
136
  "@arethetypeswrong/cli": "^0.15.0",
137
+ "jest-axe": "^8.0.0",
138
+ "rollup-plugin-preserve-shebangs": "^0.2.0",
131
139
  "@babel/core": "^7.23.0",
132
140
  "@babel/plugin-transform-runtime": "^7.23.0",
133
141
  "@babel/preset-env": "^7.23.0",
@@ -135,14 +143,13 @@
135
143
  "@babel/preset-typescript": "^7.23.0",
136
144
  "@babel/runtime-corejs3": "^7.23.0",
137
145
  "@changesets/cli": "^2.26.0",
138
- "browserslist": "^4.23.0",
139
146
  "@phosphor-icons/react": "2.1.10",
140
147
  "@rollup/plugin-babel": "^6.0.0",
141
148
  "@rollup/plugin-commonjs": "^25.0.0",
142
149
  "@rollup/plugin-node-resolve": "^15.0.0",
143
150
  "@rollup/plugin-terser": "^0.4.0",
144
151
  "@rollup/plugin-typescript": "^11.0.0",
145
- "rollup-plugin-visualizer": "^5.12.0",
152
+ "@storybook/addon-a11y": "^8.6.14",
146
153
  "@storybook/addon-essentials": "^8.6.14",
147
154
  "@storybook/addon-interactions": "^8.6.14",
148
155
  "@storybook/addon-links": "^8.6.14",
@@ -170,6 +177,8 @@
170
177
  "@typescript-eslint/eslint-plugin": "^6.0.0",
171
178
  "@typescript-eslint/parser": "^6.0.0",
172
179
  "@vitejs/plugin-react": "^4.0.0",
180
+ "@vitest/coverage-v8": "^4.0.18",
181
+ "browserslist": "^4.23.0",
173
182
  "concurrently": "^8.0.0",
174
183
  "eslint": "^8.0.0",
175
184
  "eslint-plugin-import": "^2.29.0",
@@ -189,6 +198,7 @@
189
198
  "rollup-plugin-dts": "^6.0.0",
190
199
  "rollup-plugin-peer-deps-external": "^2.2.4",
191
200
  "rollup-plugin-postcss": "^4.0.0",
201
+ "rollup-plugin-visualizer": "^5.12.0",
192
202
  "storybook": "^8.6.14",
193
203
  "storybook-theme-switch-addon": "^1.0.2",
194
204
  "ts-node": "^10.9.0",
@@ -200,19 +210,20 @@
200
210
  },
201
211
  "scripts": {
202
212
  "dev": "storybook dev -p 6006",
203
- "build": "npm run prebuild && npm run build:parallel",
213
+ "build": "npm run prebuild && npm run build:parallel && npm run postbuild",
204
214
  "build:sequential": "rollup -c",
205
215
  "build:js": "rollup -c rollup.config.build.js",
206
216
  "build:types": "rollup -c rollup.config.types.js",
207
217
  "build:styles": "rollup -c rollup.config.styles.js",
208
218
  "build:themes": "rollup -c rollup/config/themes.js",
209
219
  "build:parallel": "concurrently \"npm:build:js\" \"npm:build:types\" \"npm:build:styles\"",
220
+ "build:cli": "rollup -c rollup.config.cli.js",
221
+ "build:cli:dev": "rollup -c rollup.config.cli.js --environment NODE_ENV:development",
210
222
  "build:analyze": "ANALYZE=true rollup -c",
211
223
  "build:storybook": "storybook build",
212
224
  "test": "vitest",
213
- "test:coverage": "vitest --coverage",
214
- "test:cli": "vitest run scripts/cli/__tests__",
215
- "test:cli:watch": "vitest scripts/cli/__tests__",
225
+ "test:cli": "vitest run --config vitest.config.cli.js scripts/cli/__tests__",
226
+ "test:cli:watch": "vitest --config vitest.config.cli.js scripts/cli/__tests__",
216
227
  "test:cli:coverage": "vitest run --coverage scripts/cli/__tests__",
217
228
  "lint": "eslint src",
218
229
  "lint:fix": "eslint src --fix",
@@ -229,6 +240,7 @@
229
240
  "prebuild:with-tokens": "npm run sync:tokens && npm run validate:config",
230
241
  "verify:build": "node scripts/verify-build.js",
231
242
  "test:build": "node scripts/test-build.js",
243
+ "postbuild": "mkdir -p dist/build-tools && cp -r build-tools/* dist/build-tools/",
232
244
  "prepublishOnly": "npm run clean && npm run build && npm run attw",
233
245
  "prepack": "echo 'Preparing package for publishing...'"
234
246
  },
@@ -240,6 +252,9 @@
240
252
  "src/layouts/**/*",
241
253
  "scripts/atomix-cli.js",
242
254
  "scripts/cli/**/*",
255
+ "build-tools/**/*",
256
+ "build-tools/**/*.d.ts",
257
+ "themes/**/*",
243
258
  "atomix.config.ts",
244
259
  "README.md",
245
260
  "LICENSE",
@@ -265,7 +280,7 @@
265
280
  "type": "git",
266
281
  "url": "git+https://github.com/Shohojdhara/atomix.git"
267
282
  },
268
- "author": "liimonx <liimonx@boomdevs.com>",
283
+ "author": "liimonx <limonkhan669@gmail.com>",
269
284
  "license": "Apache-2.0",
270
285
  "funding": {
271
286
  "type": "github",
@@ -9,7 +9,7 @@ import { program } from 'commander';
9
9
  import { readFile, writeFile, mkdir, access, stat, rm } from 'fs/promises';
10
10
  import { join, dirname, basename, relative, resolve } from 'path';
11
11
  import { fileURLToPath } from 'url';
12
- import { existsSync } from 'fs';
12
+ import { existsSync, cpSync } from 'fs';
13
13
  import * as sass from 'sass';
14
14
  import postcss from 'postcss';
15
15
  import autoprefixer from 'autoprefixer';
@@ -20,6 +20,11 @@ import chokidar from 'chokidar';
20
20
  import inquirer from 'inquirer';
21
21
  import boxen from 'boxen';
22
22
  import { runInitWizard } from './cli/interactive-init.js';
23
+ import {
24
+ checkDependencies,
25
+ validateProjectStructure,
26
+ validateFrameworkConfig
27
+ } from './cli/dependency-checker.js';
23
28
  import {
24
29
  migrateTailwind,
25
30
  migrateBootstrap,
@@ -39,8 +44,6 @@ import {
39
44
  validateComponentName,
40
45
  validateThemeName,
41
46
  sanitizeInput,
42
- fileExists,
43
- isDebug as checkDebugMode,
44
47
  checkNodeVersion,
45
48
  AtomixCLIError
46
49
  } from './cli/utils.js';
@@ -54,9 +57,6 @@ import {
54
57
  generateAnimationTokens
55
58
  } from './cli/templates.js';
56
59
  import {
57
- COMPLEXITY_LEVELS,
58
- COMPONENT_FEATURES,
59
- generateComponentByComplexity,
60
60
  interactiveComponentGeneration,
61
61
  validateGeneratedComponent,
62
62
  displayValidationReport
@@ -346,17 +346,19 @@ program
346
346
 
347
347
  try {
348
348
  debug(`Generating ${type} with name: ${name}`, options);
349
- const safeName = sanitizeInput(name);
349
+ let safeName = sanitizeInput(name);
350
350
 
351
351
  if (type === 'component' || type === 'c') {
352
352
  // Handle interactive generation
353
353
  if (options.interactive) {
354
354
  const interactiveResult = await interactiveComponentGeneration();
355
355
  if (!interactiveResult) {
356
+ spinner.stop();
356
357
  return; // User cancelled
357
358
  }
358
- // Update options with interactive results
359
- Object.assign(options, interactiveResult.options);
359
+ // Update options with interactive results (name, complexity, features, outputPath)
360
+ Object.assign(options, interactiveResult);
361
+ safeName = sanitizeInput(options.name);
360
362
  }
361
363
 
362
364
  const nameValidation = validateComponentName(safeName);
@@ -408,7 +410,7 @@ program
408
410
  // Generate composable hook
409
411
  const hookPath = join(process.cwd(), 'src/lib/composables');
410
412
  if (existsSync(hookPath)) {
411
- const hookContent = componentTemplates.composable.hook(safeName);
413
+ const hookContent = componentTemplates.composable.useHook(safeName);
412
414
  const hookFilePath = join(hookPath, `use${safeName}.ts`);
413
415
 
414
416
  if (!existsSync(hookFilePath) || options.force) {
@@ -497,7 +499,7 @@ program
497
499
  // Generate settings file first
498
500
  const settingsPath = join(process.cwd(), 'src/styles/01-settings');
499
501
  if (existsSync(settingsPath)) {
500
- const settingsContent = componentTemplates.react.scssSettings(safeName);
502
+ const settingsContent = componentTemplates.react.settings(safeName);
501
503
  const settingsFilename = `_settings.${safeName.toLowerCase()}.scss`;
502
504
  const settingsFilePath = join(settingsPath, settingsFilename);
503
505
 
@@ -524,7 +526,7 @@ program
524
526
  }
525
527
 
526
528
  // Generate component SCSS file
527
- const scssContent = componentTemplates.react.scss(safeName);
529
+ const scssContent = componentTemplates.scss.component(safeName);
528
530
  const scssPath = join(process.cwd(), 'src/styles/06-components');
529
531
  const scssFilename = `_components.${safeName.toLowerCase()}.scss`;
530
532
  const scssFilePath = join(scssPath, scssFilename);
@@ -568,7 +570,7 @@ program
568
570
 
569
571
  // Generate Storybook story
570
572
  if (options.story) {
571
- const storyContent = componentTemplates.react.storyEnhanced(safeName);
573
+ const storyContent = componentTemplates.storybook.story(safeName);
572
574
  await writeFile(
573
575
  join(componentPath, `${safeName}.stories.tsx`),
574
576
  storyContent,
@@ -591,7 +593,7 @@ program
591
593
  // Post-generation validation if requested
592
594
  if (options.validate) {
593
595
  const validationResult = await validateGeneratedComponent(safeName, componentPath);
594
- const isValid = displayValidationReport(validationResult.issues, validationResult.warnings, safeName);
596
+ const isValid = displayValidationReport(validationResult);
595
597
 
596
598
  if (!isValid) {
597
599
  console.log(chalk.yellow('\n💡 Some issues were found. Consider addressing them for better component quality.'));
@@ -619,7 +621,19 @@ program
619
621
  ));
620
622
 
621
623
  } else if (type === 'hook' || type === 'h') {
622
- const componentPath = join(options.path, `use${safeName}`);
624
+ const hookPathValidation = validatePath(sanitizeInput(options.path));
625
+ if (!hookPathValidation.isValid) {
626
+ throw new AtomixCLIError(
627
+ hookPathValidation.error,
628
+ 'INVALID_PATH',
629
+ [
630
+ 'Ensure the path is within the project directory',
631
+ 'Avoid using ".." to navigate outside the project',
632
+ 'Example: --path ./src/components'
633
+ ]
634
+ );
635
+ }
636
+ const componentPath = join(hookPathValidation.safePath, `use${safeName}`);
623
637
  await mkdir(componentPath, { recursive: true });
624
638
 
625
639
  const hookContent = componentTemplates.hook.hook(safeName);
@@ -633,7 +647,19 @@ program
633
647
  spinner.succeed(chalk.green(`✓ Created hook use${safeName}`));
634
648
 
635
649
  } else if (type === 'layout' || type === 'l') {
636
- const layoutPath = join(options.path, safeName);
650
+ const layoutPathValidation = validatePath(sanitizeInput(options.path));
651
+ if (!layoutPathValidation.isValid) {
652
+ throw new AtomixCLIError(
653
+ layoutPathValidation.error,
654
+ 'INVALID_PATH',
655
+ [
656
+ 'Ensure the path is within the project directory',
657
+ 'Avoid using ".." to navigate outside the project',
658
+ 'Example: --path ./src/layouts'
659
+ ]
660
+ );
661
+ }
662
+ const layoutPath = join(layoutPathValidation.safePath, safeName);
637
663
  await mkdir(layoutPath, { recursive: true });
638
664
 
639
665
  const componentContent = componentTemplates.layout.component(safeName);
@@ -661,7 +687,19 @@ program
661
687
  spinner.succeed(chalk.green(`✓ Created layout ${safeName}`));
662
688
 
663
689
  } else if (type === 'context' || type === 'ctx') {
664
- const contextPath = join(options.path, `${safeName}Context`);
690
+ const contextPathValidation = validatePath(sanitizeInput(options.path));
691
+ if (!contextPathValidation.isValid) {
692
+ throw new AtomixCLIError(
693
+ contextPathValidation.error,
694
+ 'INVALID_PATH',
695
+ [
696
+ 'Ensure the path is within the project directory',
697
+ 'Avoid using ".." to navigate outside the project',
698
+ 'Example: --path ./src/contexts'
699
+ ]
700
+ );
701
+ }
702
+ const contextPath = join(contextPathValidation.safePath, `${safeName}Context`);
665
703
  await mkdir(contextPath, { recursive: true });
666
704
 
667
705
  const contextContent = componentTemplates.context.context(safeName);
@@ -1118,14 +1156,13 @@ program
1118
1156
  }
1119
1157
  }
1120
1158
 
1121
- // Create backup if requested
1159
+ // Create backup if requested (cross-platform: fs.cpSync works on Windows and Unix)
1122
1160
  if (options.createBackup && !options.dryRun) {
1123
1161
  const backupSpinner = ora('Creating backup...').start();
1124
1162
  const backupDir = `${sourcePath}.backup.${Date.now()}`;
1125
1163
 
1126
1164
  try {
1127
- const { execSync } = await import('child_process');
1128
- execSync(`cp -r "${sourcePath}" "${backupDir}"`, { stdio: 'ignore' });
1165
+ cpSync(sourcePath, backupDir, { recursive: true });
1129
1166
  backupSpinner.succeed(chalk.green(`✓ Backup created: ${backupDir}`));
1130
1167
  } catch (error) {
1131
1168
  backupSpinner.warn(chalk.yellow('Could not create backup, continuing anyway...'));
@@ -1680,100 +1717,142 @@ docsCommand
1680
1717
  */
1681
1718
  program
1682
1719
  .command('doctor')
1720
+ .alias('audit')
1683
1721
  .description('Diagnose common issues with your Atomix setup')
1684
1722
  .action(async () => {
1685
1723
  const spinner = ora('Running diagnostics...').start();
1686
1724
 
1687
1725
  try {
1688
- const checks = [];
1689
-
1690
- // Check Node version
1691
- const versionCheck = checkNodeVersion('18.0.0');
1692
- checks.push({
1693
- name: 'Node.js Version',
1694
- status: versionCheck.compatible ? '✅' : '❌',
1695
- message: versionCheck.compatible
1696
- ? `v${versionCheck.current} (supported)`
1697
- : `v${versionCheck.current} (requires Node ${versionCheck.required}+)`,
1726
+ const results = {
1727
+ system: [],
1728
+ dependencies: [],
1729
+ structure: [],
1730
+ framework: [],
1731
+ theme: []
1732
+ };
1733
+
1734
+ // 1. System Checks
1735
+ const nodeVersion = checkNodeVersion('18.0.0');
1736
+ results.system.push({
1737
+ name: 'Node.js',
1738
+ status: nodeVersion.compatible ? '✅' : '❌',
1739
+ message: nodeVersion.compatible
1740
+ ? `v${nodeVersion.current} (supported)`
1741
+ : `v${nodeVersion.current} (requires Node ${nodeVersion.required}+)`,
1698
1742
  });
1699
1743
 
1700
- // Check Atomix installation
1744
+ // 2. Dependency Checks
1701
1745
  const atomixPath = join(process.cwd(), 'node_modules', '@shohojdhara', 'atomix');
1702
- checks.push({
1703
- name: 'Atomix Installation',
1746
+ results.dependencies.push({
1747
+ name: 'Atomix Package',
1704
1748
  status: existsSync(atomixPath) ? '✅' : '❌',
1705
1749
  message: existsSync(atomixPath)
1706
1750
  ? 'Installed correctly'
1707
1751
  : 'Not found - run: npm install @shohojdhara/atomix',
1708
1752
  });
1709
1753
 
1710
- // Check for required dependencies
1711
- const requiredDeps = ['react', 'react-dom', 'sass'];
1712
- for (const dep of requiredDeps) {
1713
- const depPath = join(process.cwd(), 'node_modules', dep);
1714
- checks.push({
1715
- name: `Dependency: ${dep}`,
1716
- status: existsSync(depPath) ? '✅' : '⚠️',
1717
- message: existsSync(depPath)
1718
- ? 'Installed'
1719
- : 'Missing (may be required for some features)',
1754
+ const peerDeps = [
1755
+ { name: 'react', required: '>= 18.0.0' },
1756
+ { name: 'react-dom', required: '>= 18.0.0' },
1757
+ { name: 'sass', required: 'installed' }
1758
+ ];
1759
+
1760
+ for (const dep of peerDeps) {
1761
+ const depPath = join(process.cwd(), 'node_modules', dep.name);
1762
+ const exists = existsSync(depPath);
1763
+ results.dependencies.push({
1764
+ name: dep.name,
1765
+ status: exists ? '✅' : '⚠️',
1766
+ message: exists ? 'Installed' : `Missing (required: ${dep.required})`,
1720
1767
  });
1721
1768
  }
1722
1769
 
1723
- // Check for configuration files
1724
- const configFiles = ['.atomixrc', 'atomix.config.js', 'atomix.config.json', 'theme.config.ts'];
1725
- let hasConfig = false;
1726
- let configFile = null;
1770
+ // 3. Project Structure Checks
1771
+ const structureChecks = validateProjectStructure();
1772
+
1773
+ structureChecks.forEach(check => {
1774
+ let statusIcon = '✅';
1775
+ if (!check.valid && check.required) statusIcon = '❌';
1776
+ else if (!check.message.includes('exists') && !check.required) statusIcon = '⚠️';
1777
+
1778
+ results.structure.push({
1779
+ name: check.name,
1780
+ status: statusIcon,
1781
+ message: check.message.replace(/✓ |✗ |⚠ /, '')
1782
+ });
1783
+ });
1784
+
1785
+ // 4. Framework & Config Checks
1786
+ const frameworkChecks = validateFrameworkConfig();
1787
+
1788
+ frameworkChecks.forEach(check => {
1789
+ results.framework.push({
1790
+ name: check.name,
1791
+ status: check.valid ? '✅' : '💡',
1792
+ message: check.message.replace(/✓ |• /, '')
1793
+ });
1794
+ });
1795
+
1796
+ const configFiles = ['.atomixrc', 'atomix.config.js', 'atomix.config.json', 'theme.config.ts', 'atomix.config.ts'];
1797
+ let foundConfig = null;
1727
1798
  for (const file of configFiles) {
1728
1799
  if (existsSync(join(process.cwd(), file))) {
1729
- hasConfig = true;
1730
- configFile = file;
1800
+ foundConfig = file;
1731
1801
  break;
1732
1802
  }
1733
1803
  }
1734
-
1735
- checks.push({
1736
- name: 'Configuration File',
1737
- status: hasConfig ? '✅' : '💡',
1738
- message: hasConfig
1739
- ? `Configuration found (${configFile})`
1740
- : 'No config file (using defaults)',
1804
+ results.framework.push({
1805
+ name: 'Atomix Config',
1806
+ status: foundConfig ? '✅' : '💡',
1807
+ message: foundConfig ? `Found (${foundConfig})` : 'No config file (using defaults)',
1741
1808
  });
1742
1809
 
1743
- // Check theme CLI availability
1810
+ // 5. Theme CLI Checks
1744
1811
  const themeCLIAvailable = await import('./cli/theme-bridge.js')
1745
1812
  .then(m => m.isThemeCLIAvailable())
1746
1813
  .catch(() => false);
1747
1814
 
1748
- checks.push({
1749
- name: 'Theme CLI',
1815
+ results.theme.push({
1816
+ name: 'Theme Devtools',
1750
1817
  status: themeCLIAvailable ? '✅' : '⚠️',
1751
- message: themeCLIAvailable
1752
- ? 'Available'
1753
- : 'Theme devtools not found',
1818
+ message: themeCLIAvailable ? 'Available' : 'Theme devtools not found',
1754
1819
  });
1755
1820
 
1756
1821
  spinner.stop();
1757
1822
 
1758
1823
  // Display results
1759
- console.log(chalk.bold('\n🏥 Atomix Doctor Report\n'));
1760
- console.log(chalk.gray('='.repeat(50)));
1761
-
1762
- checks.forEach(check => {
1763
- console.log(`${check.status} ${chalk.bold(check.name)}`);
1764
- console.log(` ${chalk.gray(check.message)}\n`);
1824
+ console.log(chalk.bold('\n🏥 Atomix Doctor / Audit Report\n'));
1825
+
1826
+ const categories = [
1827
+ { key: 'system', label: '💻 System environment' },
1828
+ { key: 'dependencies', label: '📦 Core dependencies' },
1829
+ { key: 'structure', label: '🏗️ Project structure' },
1830
+ { key: 'framework', label: '⚙️ Configuration & Framework' },
1831
+ { key: 'theme', label: '🎨 Design System tools' }
1832
+ ];
1833
+
1834
+ categories.forEach(cat => {
1835
+ console.log(chalk.cyan.bold(`\n${cat.label}`));
1836
+ console.log(chalk.gray('-'.repeat(40)));
1837
+ results[cat.key].forEach(check => {
1838
+ console.log(` ${check.status} ${chalk.bold(check.name.padEnd(20))} ${chalk.gray(check.message)}`);
1839
+ });
1765
1840
  });
1766
1841
 
1767
- const hasIssues = checks.some(c => c.status === '❌');
1768
- const hasWarnings = checks.some(c => c.status === '⚠️');
1842
+ const hasIssues = Object.values(results).flat().some(c => c.status === '❌');
1843
+ const hasWarnings = Object.values(results).flat().some(c => c.status === '⚠️');
1769
1844
 
1845
+ console.log('\n' + chalk.gray('='.repeat(60)));
1770
1846
  if (hasIssues) {
1771
- console.log(chalk.red('\n❌ Some issues need attention'));
1847
+ console.log(chalk.red.bold('\n❌ Some critical issues need attention.'));
1848
+ console.log(chalk.gray('Check the report above and follow the suggested fixes.'));
1772
1849
  } else if (hasWarnings) {
1773
- console.log(chalk.yellow('\n⚠️ Some optional improvements available'));
1850
+ console.log(chalk.yellow.bold('\n⚠️ Your setup is functional but could be improved.'));
1851
+ console.log(chalk.gray('Recommended directories or scripts are missing.'));
1774
1852
  } else {
1775
- console.log(chalk.green('\n✅ Everything looks good!'));
1853
+ console.log(chalk.green.bold('\n✨ Everything looks great! Your project is Atomix-ready.'));
1776
1854
  }
1855
+ console.log(chalk.gray('='.repeat(60)) + '\n');
1777
1856
 
1778
1857
  } catch (error) {
1779
1858
  handleError(error, spinner);
@@ -1782,6 +1861,24 @@ program
1782
1861
 
1783
1862
 
1784
1863
 
1864
+ // Check dependencies before execution (except for doctor command)
1865
+ const args = process.argv.slice(2);
1866
+ const command = args[0];
1867
+
1868
+ // Skip dependency check for doctor command or help
1869
+ if (command !== 'doctor' && command !== '--help' && command !== '-h' && !args.includes('--help') && !args.includes('-h') && !process.env.ATOMIX_SKIP_DEP_CHECK) {
1870
+ try {
1871
+ const depResult = await checkDependencies();
1872
+ if (!depResult.success) {
1873
+ console.log(chalk.yellow('\n⚠️ Some dependencies are missing. Run `atomix doctor` for detailed information.'));
1874
+ // Don't exit - allow users to see help or run doctor
1875
+ }
1876
+ } catch (error) {
1877
+ // Silently continue if dependency check fails
1878
+ debug('Dependency check failed:', error.message);
1879
+ }
1880
+ }
1881
+
1785
1882
  // Parse arguments
1786
1883
  program.parse(process.argv);
1787
1884
 
@@ -0,0 +1,81 @@
1
+ # CLI Tests
2
+
3
+ This directory contains comprehensive tests for the Atomix CLI tools.
4
+
5
+ ## Test Structure
6
+
7
+ ### Files
8
+ - `basic.test.js` - Core utility functions (validatePath, validateComponentName, etc.)
9
+ - `utils.test.js` - Extended utility tests with file system operations
10
+ - `token-manager.test.js` - Token management functionality
11
+ - `component-generator.test.js` - Component generation and validation
12
+ - `integration.test.js` - End-to-end CLI command tests
13
+ - `test-setup.js` - Global test configuration and mocks
14
+
15
+ ## Running Tests
16
+
17
+ ### Run all CLI tests
18
+ ```bash
19
+ npm run test:cli
20
+ ```
21
+
22
+ ### Run with watch mode
23
+ ```bash
24
+ npm run test:cli:watch
25
+ ```
26
+
27
+ ### Run with coverage
28
+ ```bash
29
+ npm run test:cli:coverage
30
+ ```
31
+
32
+ ### Run specific test file
33
+ ```bash
34
+ npx vitest run scripts/cli/__tests__/basic.test.js
35
+ ```
36
+
37
+ ## Test Categories
38
+
39
+ ### Unit Tests
40
+ - **Utils**: Path validation, name validation, input sanitization
41
+ - **Token Manager**: Token parsing, validation, export/import
42
+ - **Component Generator**: Component creation, validation, templates
43
+
44
+ ### Integration Tests
45
+ - Full CLI command execution
46
+ - File system operations
47
+ - Error handling scenarios
48
+
49
+ ## Coverage Goals
50
+
51
+ - **Overall Coverage**: 80%+
52
+ - **Functions**: 80%+
53
+ - **Branches**: 80%+
54
+ - **Lines**: 80%+
55
+ - **Statements**: 80%+
56
+
57
+ ## Mock Strategy
58
+
59
+ - External dependencies (ora, chalk, inquirer) are mocked
60
+ - File system operations use temporary directories
61
+ - CLI commands are tested in isolated environments
62
+
63
+ ## Adding New Tests
64
+
65
+ 1. Create test file with `.test.js` extension
66
+ 2. Use descriptive test names
67
+ 3. Mock external dependencies
68
+ 4. Clean up temporary files in afterEach
69
+ 5. Follow existing patterns for consistency
70
+
71
+ ## Debugging Failed Tests
72
+
73
+ Run tests with verbose output:
74
+ ```bash
75
+ npx vitest run --reporter=verbose scripts/cli/__tests__/
76
+ ```
77
+
78
+ For specific test debugging:
79
+ ```bash
80
+ npx vitest run --no-coverage scripts/cli/__tests__/basic.test.js
81
+ ```