@shohojdhara/atomix 0.3.14 → 0.4.0

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 (343) 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 +44 -0
  12. package/build-tools/index.js +88 -0
  13. package/build-tools/package.json +50 -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 +21044 -2618
  20. package/dist/atomix.css.map +1 -1
  21. package/dist/atomix.min.css +77 -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 +44 -0
  33. package/dist/build-tools/index.js +88 -0
  34. package/dist/build-tools/package.json +50 -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 +152 -78
  53. package/dist/index.esm.js +346 -340
  54. package/dist/index.esm.js.map +1 -1
  55. package/dist/index.js +359 -353
  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/dist/layout.js.map +1 -1
  60. package/dist/theme.d.ts +9 -9
  61. package/dist/theme.js.map +1 -1
  62. package/package.json +23 -8
  63. package/scripts/atomix-cli.js +170 -73
  64. package/scripts/cli/__tests__/README.md +81 -0
  65. package/scripts/cli/__tests__/basic.test.js +115 -0
  66. package/scripts/cli/__tests__/component-generator.test.js +332 -0
  67. package/scripts/cli/__tests__/integration.test.js +327 -0
  68. package/scripts/cli/__tests__/test-setup.js +133 -0
  69. package/scripts/cli/__tests__/token-manager.test.js +251 -0
  70. package/scripts/cli/__tests__/utils.test.js +161 -0
  71. package/scripts/cli/component-generator.js +253 -299
  72. package/scripts/cli/dependency-checker.js +355 -0
  73. package/scripts/cli/interactive-init.js +46 -5
  74. package/scripts/cli/template-manager.js +0 -2
  75. package/scripts/cli/templates/common-templates.js +636 -0
  76. package/scripts/cli/templates/composable-templates.js +148 -126
  77. package/scripts/cli/templates/index.js +23 -16
  78. package/scripts/cli/templates/project-templates.js +151 -23
  79. package/scripts/cli/templates/react-templates.js +280 -210
  80. package/scripts/cli/templates/scss-templates.js +90 -91
  81. package/scripts/cli/templates/testing-templates.js +206 -27
  82. package/scripts/cli/templates/testing-utils.js +278 -0
  83. package/scripts/cli/templates/types-templates.js +70 -56
  84. package/scripts/cli/theme-bridge.js +8 -2
  85. package/scripts/cli/token-manager.js +318 -206
  86. package/scripts/cli/utils.js +0 -1
  87. package/src/components/Accordion/Accordion.stories.tsx +358 -850
  88. package/src/components/Accordion/Accordion.test.tsx +70 -50
  89. package/src/components/Accordion/Accordion.tsx +99 -94
  90. package/src/components/AtomixGlass/AtomixGlass.test.tsx +1 -1
  91. package/src/components/AtomixGlass/AtomixGlass.tsx +80 -39
  92. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +103 -81
  93. package/src/components/AtomixGlass/GlassFilter.tsx +9 -16
  94. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +8 -7
  95. package/src/components/AtomixGlass/glass-utils.ts +6 -5
  96. package/src/components/AtomixGlass/shader-utils.ts +133 -52
  97. package/src/components/AtomixGlass/stories/Customization.stories.tsx +131 -0
  98. package/src/components/AtomixGlass/stories/Examples.stories.tsx +2957 -2853
  99. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -1
  100. package/src/components/AtomixGlass/stories/Overview.stories.tsx +348 -0
  101. package/src/components/AtomixGlass/stories/Performance.stories.tsx +103 -0
  102. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -36
  103. package/src/components/AtomixGlass/stories/{ShaderVariants.stories.tsx → Shaders.stories.tsx} +2 -2
  104. package/src/components/AtomixGlass/stories/shared-components.tsx +90 -190
  105. package/src/components/Avatar/Avatar.stories.tsx +195 -0
  106. package/src/components/Avatar/Avatar.tsx +58 -56
  107. package/src/components/Badge/Badge.stories.tsx +122 -352
  108. package/src/components/Badge/Badge.test.tsx +41 -41
  109. package/src/components/Badge/Badge.tsx +64 -62
  110. package/src/components/Block/Block.stories.tsx +30 -11
  111. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +142 -23
  112. package/src/components/Breadcrumb/Breadcrumb.tsx +62 -60
  113. package/src/components/Button/Button.stories.tsx +454 -1126
  114. package/src/components/Button/Button.test.tsx +123 -0
  115. package/src/components/Button/Button.tsx +88 -60
  116. package/src/components/Button/ButtonGroup.stories.tsx +376 -215
  117. package/src/components/Button/ButtonGroup.tsx +4 -15
  118. package/src/components/Callout/Callout.stories.tsx +316 -568
  119. package/src/components/Card/Card.stories.tsx +292 -81
  120. package/src/components/Card/Card.tsx +30 -14
  121. package/src/components/Chart/AreaChart.tsx +1 -1
  122. package/src/components/Chart/CandlestickChart.tsx +23 -16
  123. package/src/components/Chart/Chart.stories.tsx +153 -16
  124. package/src/components/Chart/Chart.tsx +40 -44
  125. package/src/components/Chart/ChartRenderer.tsx +39 -12
  126. package/src/components/Chart/ChartToolbar.tsx +21 -5
  127. package/src/components/Chart/DonutChart.tsx +1 -1
  128. package/src/components/Chart/FunnelChart.tsx +4 -1
  129. package/src/components/Chart/GaugeChart.tsx +3 -1
  130. package/src/components/Chart/HeatmapChart.tsx +50 -37
  131. package/src/components/Chart/LineChart.tsx +3 -2
  132. package/src/components/Chart/MultiAxisChart.tsx +24 -16
  133. package/src/components/Chart/RadarChart.tsx +19 -17
  134. package/src/components/Chart/ScatterChart.tsx +29 -21
  135. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +152 -66
  136. package/src/components/ColorModeToggle/ColorModeToggle.tsx +15 -3
  137. package/src/components/Countdown/Countdown.stories.tsx +114 -7
  138. package/src/components/DataTable/DataTable.stories.tsx +349 -144
  139. package/src/components/DataTable/DataTable.test.tsx +26 -148
  140. package/src/components/DataTable/DataTable.tsx +485 -456
  141. package/src/components/DatePicker/DatePicker.stories.tsx +310 -1066
  142. package/src/components/DatePicker/DatePicker.tsx +31 -26
  143. package/src/components/Dropdown/Dropdown.stories.tsx +153 -36
  144. package/src/components/Dropdown/Dropdown.tsx +313 -299
  145. package/src/components/EdgePanel/EdgePanel.stories.tsx +221 -25
  146. package/src/components/EdgePanel/EdgePanel.tsx +1 -3
  147. package/src/components/Footer/Footer.stories.tsx +396 -327
  148. package/src/components/Footer/Footer.tsx +130 -128
  149. package/src/components/Footer/FooterLink.tsx +2 -2
  150. package/src/components/Form/Checkbox.stories.tsx +140 -6
  151. package/src/components/Form/Checkbox.test.tsx +63 -0
  152. package/src/components/Form/Checkbox.tsx +122 -78
  153. package/src/components/Form/Form.stories.tsx +110 -19
  154. package/src/components/Form/FormGroup.stories.tsx +127 -4
  155. package/src/components/Form/Input.stories.tsx +22 -39
  156. package/src/components/Form/Input.test.tsx +38 -44
  157. package/src/components/Form/Radio.stories.tsx +146 -17
  158. package/src/components/Form/Radio.tsx +68 -66
  159. package/src/components/Form/Select.stories.tsx +140 -8
  160. package/src/components/Form/Select.tsx +184 -182
  161. package/src/components/Form/Textarea.stories.tsx +149 -6
  162. package/src/components/Form/Textarea.test.tsx +27 -32
  163. package/src/components/Hero/Hero.stories.tsx +372 -38
  164. package/src/components/Hero/Hero.tsx +201 -55
  165. package/src/components/Icon/index.ts +7 -1
  166. package/src/components/List/List.stories.tsx +141 -3
  167. package/src/components/List/List.tsx +19 -23
  168. package/src/components/Modal/Modal.stories.tsx +183 -43
  169. package/src/components/Modal/Modal.tsx +130 -127
  170. package/src/components/Navigation/Menu/MegaMenu.tsx +70 -70
  171. package/src/components/Navigation/Nav/NavDropdown.tsx +1 -5
  172. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +128 -28
  173. package/src/components/Navigation/SideMenu/SideMenu.tsx +5 -7
  174. package/src/components/Navigation/SideMenu/SideMenuItem.tsx +4 -5
  175. package/src/components/Pagination/Pagination.stories.tsx +7 -4
  176. package/src/components/Pagination/Pagination.tsx +199 -202
  177. package/src/components/PhotoViewer/PhotoViewer.tsx +4 -1
  178. package/src/components/Popover/Popover.stories.tsx +354 -97
  179. package/src/components/Popover/Popover.tsx +41 -37
  180. package/src/components/Progress/Progress.stories.tsx +160 -7
  181. package/src/components/River/River.stories.tsx +3 -2
  182. package/src/components/SectionIntro/SectionIntro.stories.tsx +239 -47
  183. package/src/components/Slider/Slider.stories.tsx +12 -4
  184. package/src/components/Spinner/Spinner.stories.tsx +104 -8
  185. package/src/components/Spinner/Spinner.test.tsx +23 -23
  186. package/src/components/Spinner/Spinner.tsx +43 -46
  187. package/src/components/Steps/Steps.stories.tsx +173 -42
  188. package/src/components/Tabs/Tabs.stories.tsx +141 -12
  189. package/src/components/Tabs/Tabs.tsx +74 -72
  190. package/src/components/Testimonial/Testimonial.stories.tsx +120 -3
  191. package/src/components/Todo/Todo.stories.tsx +198 -9
  192. package/src/components/Toggle/Toggle.stories.tsx +137 -36
  193. package/src/components/Toggle/Toggle.test.tsx +65 -70
  194. package/src/components/Toggle/Toggle.tsx +4 -1
  195. package/src/components/Tooltip/Tooltip.stories.tsx +194 -100
  196. package/src/components/Tooltip/Tooltip.tsx +104 -106
  197. package/src/components/Upload/Upload.stories.tsx +241 -150
  198. package/src/components/Upload/Upload.tsx +287 -283
  199. package/src/components/VideoPlayer/VideoPlayer.tsx +6 -1
  200. package/src/components/index.ts +13 -2
  201. package/src/layouts/Grid/Grid.stories.tsx +9 -3
  202. package/src/layouts/MasonryGrid/MasonryGrid.tsx +5 -1
  203. package/src/lib/README.md +2 -2
  204. package/src/lib/__tests__/theme-tools.test.ts +219 -0
  205. package/src/lib/composables/index.ts +2 -2
  206. package/src/lib/composables/shared-mouse-tracker.ts +13 -14
  207. package/src/lib/composables/useAtomixGlass.ts +126 -97
  208. package/src/lib/composables/useChartExport.ts +3 -8
  209. package/src/lib/composables/useDataTable.ts +72 -43
  210. package/src/lib/composables/useHero.ts +58 -14
  211. package/src/lib/composables/useHeroBackgroundSlider.ts +2 -9
  212. package/src/lib/composables/useInput.ts +10 -8
  213. package/src/lib/composables/useSideMenu.ts +6 -5
  214. package/src/lib/composables/useTooltip.ts +1 -2
  215. package/src/lib/composables/useVideoPlayer.ts +44 -35
  216. package/src/lib/config/index.ts +154 -154
  217. package/src/lib/constants/components.ts +9 -32
  218. package/src/lib/constants/cssVariables.ts +29 -29
  219. package/src/lib/hooks/__tests__/useComponentCustomization.test.ts +2 -6
  220. package/src/lib/hooks/index.ts +1 -1
  221. package/src/lib/hooks/useComponentCustomization.ts +11 -17
  222. package/src/lib/hooks/usePerformanceMonitor.ts +6 -7
  223. package/src/lib/patterns/__tests__/slots.test.ts +1 -1
  224. package/src/lib/patterns/index.ts +1 -1
  225. package/src/lib/patterns/slots.tsx +8 -13
  226. package/src/lib/storybook/InteractiveDemo.tsx +13 -18
  227. package/src/lib/storybook/PreviewContainer.tsx +1 -1
  228. package/src/lib/storybook/VariantsGrid.tsx +3 -7
  229. package/src/lib/storybook/index.ts +1 -1
  230. package/src/lib/theme/adapters/cssVariableMapper.ts +47 -74
  231. package/src/lib/theme/adapters/index.ts +3 -9
  232. package/src/lib/theme/adapters/themeAdapter.ts +41 -26
  233. package/src/lib/theme/config/index.ts +1 -1
  234. package/src/lib/theme/config/types.ts +2 -2
  235. package/src/lib/theme/config/validator.ts +10 -5
  236. package/src/lib/theme/constants/constants.ts +2 -2
  237. package/src/lib/theme/constants/index.ts +1 -2
  238. package/src/lib/theme/core/__tests__/createTheme.test.ts +20 -22
  239. package/src/lib/theme/core/composeTheme.ts +32 -26
  240. package/src/lib/theme/core/createTheme.ts +1 -1
  241. package/src/lib/theme/core/createThemeObject.ts +308 -301
  242. package/src/lib/theme/core/index.ts +3 -3
  243. package/src/lib/theme/devtools/CLI.ts +107 -105
  244. package/src/lib/theme/devtools/Comparator.tsx +50 -32
  245. package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +50 -48
  246. package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +257 -63
  247. package/src/lib/theme/devtools/Inspector.tsx +75 -60
  248. package/src/lib/theme/devtools/LiveEditor.tsx +97 -76
  249. package/src/lib/theme/devtools/Preview.tsx +150 -106
  250. package/src/lib/theme/devtools/ThemeValidator.ts +29 -21
  251. package/src/lib/theme/devtools/index.ts +3 -9
  252. package/src/lib/theme/devtools/useHistory.ts +23 -21
  253. package/src/lib/theme/errors/errors.ts +12 -11
  254. package/src/lib/theme/errors/index.ts +2 -7
  255. package/src/lib/theme/generators/generateCSS.ts +9 -13
  256. package/src/lib/theme/generators/generateCSSNested.ts +1 -6
  257. package/src/lib/theme/generators/generateCSSVariables.ts +673 -630
  258. package/src/lib/theme/generators/index.ts +1 -4
  259. package/src/lib/theme/i18n/index.ts +1 -1
  260. package/src/lib/theme/i18n/rtl.ts +13 -13
  261. package/src/lib/theme/index.ts +7 -16
  262. package/src/lib/theme/runtime/ThemeApplicator.ts +4 -4
  263. package/src/lib/theme/runtime/ThemeContext.tsx +1 -1
  264. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +19 -23
  265. package/src/lib/theme/runtime/ThemeProvider.tsx +230 -239
  266. package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +1 -1
  267. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +24 -29
  268. package/src/lib/theme/runtime/index.ts +2 -5
  269. package/src/lib/theme/runtime/useTheme.ts +18 -18
  270. package/src/lib/theme/runtime/useThemeTokens.ts +22 -22
  271. package/src/lib/theme/test/testTheme.ts +15 -16
  272. package/src/lib/theme/tokens/index.ts +2 -7
  273. package/src/lib/theme/tokens/tokens.ts +25 -24
  274. package/src/lib/theme/types.ts +428 -411
  275. package/src/lib/theme/utils/__tests__/themeValidation.test.ts +3 -3
  276. package/src/lib/theme/utils/componentTheming.ts +18 -18
  277. package/src/lib/theme/utils/domUtils.ts +277 -289
  278. package/src/lib/theme/utils/index.ts +1 -2
  279. package/src/lib/theme/utils/injectCSS.ts +10 -14
  280. package/src/lib/theme/utils/naming.ts +20 -16
  281. package/src/lib/theme/utils/themeHelpers.ts +10 -12
  282. package/src/lib/theme/utils/themeUtils.ts +85 -86
  283. package/src/lib/theme/utils/themeValidation.ts +82 -33
  284. package/src/lib/theme-tools.ts +8 -6
  285. package/src/lib/types/components.ts +172 -71
  286. package/src/lib/types/partProps.ts +1 -1
  287. package/src/lib/utils/__tests__/csv.test.ts +45 -0
  288. package/src/lib/utils/componentUtils.ts +8 -12
  289. package/src/lib/utils/csv.ts +19 -0
  290. package/src/lib/utils/dataTableExport.ts +2 -15
  291. package/src/lib/utils/fontPreloader.ts +10 -19
  292. package/src/lib/utils/icons.ts +4 -1
  293. package/src/lib/utils/index.ts +2 -6
  294. package/src/lib/utils/memoryMonitor.ts +10 -8
  295. package/src/lib/utils/themeNaming.ts +2 -2
  296. package/src/styles/01-settings/_index.scss +1 -1
  297. package/src/styles/01-settings/_settings.accordion.scss +28 -7
  298. package/src/styles/01-settings/_settings.colors.scss +11 -11
  299. package/src/styles/01-settings/_settings.design-tokens.scss +61 -50
  300. package/src/styles/01-settings/_settings.navbar.scss +1 -1
  301. package/src/styles/01-settings/_settings.spacing.scss +3 -4
  302. package/src/styles/01-settings/_settings.tooltip.scss +1 -1
  303. package/src/styles/01-settings/_settings.typography.scss +4 -4
  304. package/src/styles/02-tools/_tools.button.scss +51 -21
  305. package/src/styles/02-tools/_tools.utility-api.scss +38 -12
  306. package/src/styles/03-generic/_generic.root.scss +4 -3
  307. package/src/styles/06-components/_components.accordion.scss +56 -14
  308. package/src/styles/06-components/_components.atomix-glass.scss +13 -9
  309. package/src/styles/06-components/_components.button.scss +16 -4
  310. package/src/styles/06-components/_components.callout.scss +27 -21
  311. package/src/styles/06-components/_components.card.scss +5 -14
  312. package/src/styles/06-components/_components.chart.scss +22 -19
  313. package/src/styles/06-components/_components.checkbox.scss +25 -17
  314. package/src/styles/06-components/_components.color-mode-toggle.scss +3 -1
  315. package/src/styles/06-components/_components.edge-panel.scss +9 -2
  316. package/src/styles/06-components/_components.footer.scss +1 -1
  317. package/src/styles/06-components/_components.side-menu.scss +5 -5
  318. package/src/styles/06-components/_components.toggle.scss +18 -0
  319. package/src/styles/06-components/_index.scss +1 -1
  320. package/src/styles/06-components/old.chart.styles.scss +0 -2
  321. package/src/styles/99-utilities/_index.scss +2 -0
  322. package/src/styles/99-utilities/_utilities.border.scss +69 -27
  323. package/src/styles/99-utilities/_utilities.display.scss +1 -1
  324. package/src/styles/99-utilities/_utilities.opacity.scss +10 -0
  325. package/src/styles/99-utilities/_utilities.position.scss +16 -9
  326. package/src/styles/99-utilities/_utilities.scss +2 -0
  327. package/src/styles/99-utilities/_utilities.sizes.scss +47 -18
  328. package/src/styles/99-utilities/_utilities.spacing.scss +118 -66
  329. package/src/styles/99-utilities/_utilities.text-gradient.scss +45 -0
  330. package/src/styles/99-utilities/_utilities.text.scss +67 -46
  331. package/themes/dark-complementary/README.md +98 -0
  332. package/themes/dark-complementary/index.scss +158 -0
  333. package/themes/default-light/README.md +81 -0
  334. package/themes/default-light/index.scss +154 -0
  335. package/themes/high-contrast/README.md +105 -0
  336. package/themes/high-contrast/index.scss +172 -0
  337. package/themes/test-theme/README.md +38 -0
  338. package/themes/test-theme/index.scss +47 -0
  339. package/scripts/cli/templates-original-backup.js +0 -1655
  340. package/scripts/cli/templates_backup.js +0 -684
  341. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +0 -1438
  342. package/src/lib/composables/useButton.ts +0 -93
  343. package/src/lib/composables/useCheckbox.ts +0 -70
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Basic CLI Tests - Core Functionality
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import {
7
+ validatePath,
8
+ validateComponentName,
9
+ validateThemeName,
10
+ sanitizeInput,
11
+ AtomixCLIError
12
+ } from '../utils.js';
13
+
14
+ describe('CLI Core Utils', () => {
15
+ describe('validatePath', () => {
16
+ it('should accept valid relative paths', () => {
17
+ const result = validatePath('./src/components', '/project');
18
+ expect(result.isValid).toBe(true);
19
+ });
20
+
21
+ it('should reject paths outside project directory', () => {
22
+ const result = validatePath('../../etc/passwd', '/project');
23
+ expect(result.isValid).toBe(false);
24
+ expect(result.error).toContain('outside the project directory');
25
+ });
26
+
27
+ it('should reject sensitive files', () => {
28
+ const result = validatePath('.env', '/project');
29
+ expect(result.isValid).toBe(false);
30
+ expect(result.error).toContain('sensitive path');
31
+ });
32
+ });
33
+
34
+ describe('validateComponentName', () => {
35
+ it('should accept valid PascalCase names', () => {
36
+ const validNames = ['Button', 'CardHeader', 'ModalDialog'];
37
+
38
+ validNames.forEach(name => {
39
+ const result = validateComponentName(name);
40
+ expect(result.isValid).toBe(true);
41
+ });
42
+ });
43
+
44
+ it('should reject invalid names', () => {
45
+ const invalidNames = ['button', 'button-primary', 'Button-Primary', '123Button', ''];
46
+
47
+ invalidNames.forEach(name => {
48
+ const result = validateComponentName(name);
49
+ expect(result.isValid).toBe(false);
50
+ });
51
+ });
52
+
53
+ it('should reject reserved words', () => {
54
+ const reservedWords = ['Component', 'React', 'Fragment'];
55
+
56
+ reservedWords.forEach(name => {
57
+ const result = validateComponentName(name);
58
+ expect(result.isValid).toBe(false);
59
+ });
60
+ });
61
+ });
62
+
63
+ describe('validateThemeName', () => {
64
+ it('should accept valid kebab-case names', () => {
65
+ const validNames = ['dark-theme', 'light', 'high-contrast'];
66
+
67
+ validNames.forEach(name => {
68
+ const result = validateThemeName(name);
69
+ expect(result.isValid).toBe(true);
70
+ });
71
+ });
72
+
73
+ it('should reject invalid theme names', () => {
74
+ const invalidNames = ['DarkTheme', 'theme_dark', 'Theme-Dark', '123theme', ''];
75
+
76
+ invalidNames.forEach(name => {
77
+ const result = validateThemeName(name);
78
+ expect(result.isValid).toBe(false);
79
+ });
80
+ });
81
+ });
82
+
83
+ describe('sanitizeInput', () => {
84
+ it('should remove dangerous shell characters', () => {
85
+ const dangerousInputs = [
86
+ 'test; rm -rf /',
87
+ 'input && malicious-command',
88
+ 'command | pipe'
89
+ ];
90
+
91
+ dangerousInputs.forEach(input => {
92
+ const sanitized = sanitizeInput(input);
93
+ expect(sanitized).not.toMatch(/[;&|`$<>]/);
94
+ });
95
+ });
96
+
97
+ it('should preserve safe characters', () => {
98
+ const safeInput = 'Button-Component_123';
99
+ const sanitized = sanitizeInput(safeInput);
100
+ expect(sanitized).toBe(safeInput);
101
+ });
102
+ });
103
+
104
+ describe('AtomixCLIError', () => {
105
+ it('should create error with code and suggestions', () => {
106
+ const suggestions = ['Use PascalCase', 'Start with letter'];
107
+ const error = new AtomixCLIError('Invalid name', 'INVALID_NAME', suggestions);
108
+
109
+ expect(error.message).toBe('Invalid name');
110
+ expect(error.code).toBe('INVALID_NAME');
111
+ expect(error.suggestions).toEqual(suggestions);
112
+ expect(error.name).toBe('AtomixCLIError');
113
+ });
114
+ });
115
+ });
@@ -0,0 +1,332 @@
1
+ /**
2
+ * Component Generator Tests
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
6
+ import {
7
+ generateComponentByComplexity,
8
+ interactiveComponentGeneration,
9
+ validateGeneratedComponent,
10
+ displayValidationReport
11
+ } from '../component-generator.js';
12
+ import { mkdtemp, rm, writeFile, mkdir } from 'fs/promises';
13
+ import { join } from 'path';
14
+ import { tmpdir } from 'os';
15
+
16
+ // Mock dependencies
17
+ vi.mock('ora', () => ({
18
+ default: vi.fn(() => ({
19
+ start: vi.fn(() => ({
20
+ succeed: vi.fn(),
21
+ fail: vi.fn(),
22
+ text: ''
23
+ }))
24
+ }))
25
+ }));
26
+
27
+ vi.mock('inquirer', async () => {
28
+ const actual = await vi.importActual('inquirer');
29
+ return {
30
+ ...actual,
31
+ default: {
32
+ prompt: vi.fn()
33
+ }
34
+ };
35
+ });
36
+
37
+ vi.mock('chalk', () => {
38
+ const bold = vi.fn((text) => text);
39
+ bold.cyan = vi.fn((text) => text);
40
+ bold.green = vi.fn((text) => text);
41
+ bold.yellow = vi.fn((text) => text);
42
+ bold.red = vi.fn((text) => text);
43
+
44
+ return {
45
+ default: {
46
+ green: vi.fn((text) => text),
47
+ red: vi.fn((text) => text),
48
+ yellow: vi.fn((text) => text),
49
+ cyan: vi.fn((text) => text),
50
+ gray: vi.fn((text) => text),
51
+ bold: bold
52
+ }
53
+ };
54
+ });
55
+
56
+ describe('Component Generator', () => {
57
+ let tempDir;
58
+ let componentsDir;
59
+
60
+ beforeEach(async () => {
61
+ tempDir = await mkdtemp(join(tmpdir(), 'atomix-test-'));
62
+ componentsDir = join(tempDir, 'src', 'components');
63
+ await mkdir(componentsDir, { recursive: true });
64
+ });
65
+
66
+ afterEach(async () => {
67
+ await rm(tempDir, { recursive: true, force: true });
68
+ vi.clearAllMocks();
69
+ });
70
+
71
+ describe('generateComponentByComplexity', () => {
72
+ it('should generate simple component', async () => {
73
+ const componentName = 'SimpleButton';
74
+ const options = {
75
+ typescript: true,
76
+ story: false,
77
+ test: false,
78
+ path: componentsDir
79
+ };
80
+
81
+ const result = generateComponentByComplexity(componentName, 'simple', options);
82
+
83
+ // Check returned template content
84
+ expect(result).toContain('export const SimpleButton');
85
+ expect(result).toContain('forwardRef');
86
+ });
87
+
88
+ it('should generate medium complexity component', async () => {
89
+ const componentName = 'MediumCard';
90
+ const options = {
91
+ typescript: true,
92
+ story: true,
93
+ test: false,
94
+ path: componentsDir
95
+ };
96
+
97
+ const result = generateComponentByComplexity(componentName, 'medium', options);
98
+
99
+ // Check returned template content
100
+ expect(result).toContain('useId');
101
+ expect(result).toContain('MediumCardProps');
102
+ });
103
+
104
+ it('should generate complex component', async () => {
105
+ const componentName = 'ComplexModal';
106
+ const options = {
107
+ typescript: true,
108
+ story: true,
109
+ test: true,
110
+ path: componentsDir
111
+ };
112
+
113
+ const result = generateComponentByComplexity(componentName, 'complex', options);
114
+
115
+ // Check returned template content
116
+ expect(result).toContain('useId');
117
+ expect(result).toContain('AtomixGlass');
118
+ expect(result).toContain('ComplexModalProps');
119
+ });
120
+
121
+ it('should generate SCSS files', async () => {
122
+ // Note: generateComponentByComplexity returns component template only
123
+ // SCSS generation is handled separately by the CLI
124
+ const componentName = 'StyledButton';
125
+ const options = {
126
+ typescript: true,
127
+ scssModule: false,
128
+ path: componentsDir
129
+ };
130
+
131
+ const result = generateComponentByComplexity(componentName, 'simple', options);
132
+
133
+ // Should return valid component code
134
+ expect(result).toContain('export const StyledButton');
135
+ expect(result).toContain('forwardRef');
136
+ });
137
+
138
+ it('should generate Storybook stories', async () => {
139
+ // Note: Story files are generated separately by the CLI
140
+ const componentName = 'StoryComponent';
141
+ const options = {
142
+ typescript: true,
143
+ story: true,
144
+ path: componentsDir
145
+ };
146
+
147
+ const result = generateComponentByComplexity(componentName, 'simple', options);
148
+
149
+ // Should return valid component code that can be used in stories
150
+ expect(result).toContain('export const StoryComponent');
151
+ });
152
+
153
+ it('should generate test files', async () => {
154
+ // Note: Test files are generated separately by the CLI
155
+ const componentName = 'TestComponent';
156
+ const options = {
157
+ typescript: true,
158
+ test: true,
159
+ path: componentsDir
160
+ };
161
+
162
+ const result = generateComponentByComplexity(componentName, 'simple', options);
163
+
164
+ // Should return valid component code that can be tested
165
+ expect(result).toContain('export const TestComponent');
166
+ });
167
+ });
168
+
169
+ describe('interactiveComponentGeneration', () => {
170
+ it('should prompt for component details', async () => {
171
+ const inquirer = (await import('inquirer')).default;
172
+ inquirer.prompt.mockResolvedValue({
173
+ componentName: 'InteractiveButton',
174
+ complexity: 'medium',
175
+ features: ['typescript', 'story', 'test'],
176
+ outputPath: './src/components'
177
+ });
178
+
179
+ const result = await interactiveComponentGeneration();
180
+
181
+ expect(result).toEqual({
182
+ name: 'InteractiveButton',
183
+ complexity: 'medium',
184
+ features: ['typescript', 'story', 'test'],
185
+ outputPath: './src/components'
186
+ });
187
+
188
+ expect(inquirer.prompt).toHaveBeenCalledWith(
189
+ expect.arrayContaining([
190
+ expect.objectContaining({
191
+ name: 'componentName',
192
+ type: 'input'
193
+ })
194
+ ])
195
+ );
196
+ });
197
+
198
+ it('should handle cancellation', async () => {
199
+ const inquirer = (await import('inquirer')).default;
200
+ inquirer.prompt.mockRejectedValue(new Error('User cancelled'));
201
+
202
+ const result = await interactiveComponentGeneration();
203
+ expect(result).toBeNull();
204
+ });
205
+ });
206
+
207
+ describe('validateGeneratedComponent', () => {
208
+ it('should validate component structure', async () => {
209
+ const componentName = 'ValidComponent';
210
+ const componentPath = join(componentsDir, componentName);
211
+
212
+ // Create valid component structure
213
+ await mkdir(componentPath, { recursive: true });
214
+ await writeFile(join(componentPath, `${componentName}.tsx`), `
215
+ import React, { forwardRef } from 'react';
216
+
217
+ export const ValidComponent = forwardRef<HTMLDivElement, ValidComponentProps>(
218
+ ({ children }, ref) => {
219
+ return <div ref={ref}>{children}</div>;
220
+ }
221
+ );
222
+
223
+ export interface ValidComponentProps {
224
+ children?: React.ReactNode;
225
+ }
226
+ `);
227
+
228
+ const validation = await validateGeneratedComponent(componentName, componentPath);
229
+
230
+ expect(validation.issues).toHaveLength(0);
231
+ expect(validation.valid).toBe(true);
232
+ });
233
+
234
+ it('should detect missing TypeScript interface', async () => {
235
+ const componentName = 'InvalidComponent';
236
+ const componentPath = join(componentsDir, componentName);
237
+
238
+ await mkdir(componentPath, { recursive: true });
239
+ await writeFile(join(componentPath, `${componentName}.tsx`), `
240
+ export const InvalidComponent = ({ children }) => {
241
+ return <div>{children}</div>;
242
+ };
243
+ `);
244
+
245
+ const validation = await validateGeneratedComponent(componentName, componentPath);
246
+
247
+ expect(validation.issues).toEqual(
248
+ expect.arrayContaining([
249
+ expect.objectContaining({ issue: 'Missing TypeScript type definitions' })
250
+ ])
251
+ );
252
+ expect(validation.valid).toBe(false);
253
+ });
254
+
255
+ it('should detect missing accessibility attributes', async () => {
256
+ const componentName = 'InaccessibleComponent';
257
+ const componentPath = join(componentsDir, componentName);
258
+
259
+ await mkdir(componentPath, { recursive: true });
260
+ await writeFile(join(componentPath, `${componentName}.tsx`), `
261
+ export const InaccessibleComponent = () => {
262
+ return <button>Click me</button>;
263
+ };
264
+ `);
265
+
266
+ const validation = await validateGeneratedComponent(componentName, componentPath);
267
+
268
+ expect(validation.warnings).toEqual(
269
+ expect.arrayContaining([
270
+ expect.objectContaining({ issue: 'Missing accessibility attributes' })
271
+ ])
272
+ );
273
+ });
274
+
275
+ it('should detect missing design tokens', async () => {
276
+ const componentName = 'HardcodedComponent';
277
+ const componentPath = join(componentsDir, componentName);
278
+
279
+ await mkdir(componentPath, { recursive: true });
280
+ await writeFile(join(componentPath, `${componentName}.tsx`), `
281
+ export const HardcodedComponent = () => {
282
+ return <div style={{ color: '#ff0000', padding: '16px' }}>Content</div>;
283
+ };
284
+ `);
285
+
286
+ const validation = await validateGeneratedComponent(componentName, componentPath);
287
+
288
+ expect(validation.warnings).toEqual(
289
+ expect.arrayContaining([
290
+ expect.objectContaining({ issue: 'Using hardcoded values instead of design tokens' })
291
+ ])
292
+ );
293
+ });
294
+ });
295
+
296
+ describe('displayValidationReport', () => {
297
+ it('should display validation report with issues', () => {
298
+ const issues = ['Missing interface', 'No accessibility'];
299
+ const warnings = ['Hardcoded styles'];
300
+
301
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
302
+
303
+ displayValidationReport({
304
+ valid: false,
305
+ issues: issues.map(i => ({ file: 'test', issue: i, suggestion: 'fix' })),
306
+ warnings: warnings.map(w => ({ file: 'test', issue: w, suggestion: 'fix' }))
307
+ });
308
+
309
+ expect(consoleSpy).toHaveBeenCalledWith(
310
+ expect.stringContaining('❌ Found 2 issue(s):')
311
+ );
312
+ expect(consoleSpy).toHaveBeenCalledWith(
313
+ expect.stringContaining('⚠️ Found 1 warning(s):')
314
+ );
315
+
316
+ consoleSpy.mockRestore();
317
+ });
318
+
319
+ it('should display success message for valid components', () => {
320
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
321
+
322
+ const isValid = displayValidationReport({ valid: true, issues: [], warnings: [] });
323
+
324
+ expect(isValid).toBe(true);
325
+ expect(consoleSpy).toHaveBeenCalledWith(
326
+ expect.stringContaining('✅ Component validation passed!')
327
+ );
328
+
329
+ consoleSpy.mockRestore();
330
+ });
331
+ });
332
+ });