create-lumen 1.1.3 → 1.2.0-beta.1

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 (247) hide show
  1. package/README.md +43 -35
  2. package/package.json +8 -2
  3. package/src/configure.js +29 -15
  4. package/src/css.js +73 -14
  5. package/src/dependencies.js +8 -3
  6. package/src/format.js +28 -0
  7. package/src/injector.js +131 -28
  8. package/src/main.js +17 -1
  9. package/src/readme.js +65 -22
  10. package/templates/architectures/component-based/main.tsx +1 -1
  11. package/templates/architectures/component-based/src/App.jsx +6 -4
  12. package/templates/architectures/component-based/src/App.tsx +6 -4
  13. package/templates/architectures/component-based/src/components/common/Button.jsx +5 -4
  14. package/templates/architectures/component-based/src/components/common/Button.tsx +5 -4
  15. package/templates/architectures/component-based/src/hooks/useApp.js +10 -0
  16. package/templates/architectures/component-based/src/hooks/useApp.ts +10 -0
  17. package/templates/architectures/component-based/src/hooks/useLocalStorage.ts +5 -5
  18. package/templates/architectures/component-based/src/layouts/MainLayout.jsx +12 -6
  19. package/templates/architectures/component-based/src/layouts/MainLayout.tsx +12 -6
  20. package/templates/architectures/component-based/src/pages/Home/Home.jsx +6 -2
  21. package/templates/architectures/component-based/src/pages/Home/Home.tsx +6 -2
  22. package/templates/architectures/component-based/src/providers/AppProvider.jsx +20 -0
  23. package/templates/architectures/component-based/src/providers/AppProvider.tsx +24 -0
  24. package/templates/architectures/component-based/src/providers/appcontext.js +3 -0
  25. package/templates/architectures/component-based/src/providers/appcontext.ts +8 -0
  26. package/templates/architectures/{feature-based → component-based}/src/types/index.js +7 -0
  27. package/templates/architectures/{feature-based → component-based}/src/types/index.ts +5 -0
  28. package/templates/architectures/component-based/src/utils/cn.ts +3 -1
  29. package/templates/architectures/feature-based/main.jsx +1 -1
  30. package/templates/architectures/feature-based/main.tsx +2 -2
  31. package/templates/architectures/feature-based/scripts/create-feature.mjs +2 -2
  32. package/templates/architectures/feature-based/src/app/App.jsx +15 -5
  33. package/templates/architectures/feature-based/src/app/App.tsx +15 -5
  34. package/templates/architectures/feature-based/src/app/contexts/themecontext.js +3 -0
  35. package/templates/architectures/feature-based/src/app/contexts/themecontext.ts +8 -0
  36. package/templates/architectures/feature-based/src/app/hooks/useTheme.js +10 -0
  37. package/templates/architectures/feature-based/src/app/hooks/useTheme.ts +10 -0
  38. package/templates/architectures/feature-based/src/app/providers/ThemeProvider.jsx +17 -2
  39. package/templates/architectures/feature-based/src/app/providers/ThemeProvider.tsx +20 -3
  40. package/templates/architectures/feature-based/src/features/home/pages/HomePage.jsx +18 -5
  41. package/templates/architectures/feature-based/src/features/home/pages/HomePage.tsx +18 -5
  42. package/templates/architectures/feature-based/src/shared/components/ui/Button.jsx +31 -0
  43. package/templates/architectures/feature-based/src/shared/components/ui/Button.tsx +36 -0
  44. package/templates/architectures/feature-based/src/{hooks → shared/hooks}/useLocalStorage.ts +5 -5
  45. package/templates/architectures/feature-based/src/shared/layouts/.gitkeep +0 -0
  46. package/templates/architectures/feature-based/src/shared/stores/.gitkeep +0 -0
  47. package/templates/architectures/feature-based/src/shared/styles/.gitkeep +0 -0
  48. package/templates/architectures/feature-based/src/shared/types/index.js +20 -0
  49. package/templates/architectures/feature-based/src/shared/types/index.ts +16 -0
  50. package/templates/architectures/feature-based/src/shared/utils/cn.ts +5 -0
  51. package/templates/conditional/axios/component-based/src/config/axios.config.js +7 -0
  52. package/templates/conditional/axios/component-based/src/config/axios.config.ts +7 -0
  53. package/templates/conditional/axios/component-based/src/services/axios.client.js +24 -0
  54. package/templates/conditional/axios/component-based/src/services/axios.client.ts +24 -0
  55. package/templates/conditional/axios/component-based/src/services/user.service.js +33 -0
  56. package/templates/conditional/axios/component-based/src/services/user.service.ts +29 -0
  57. package/templates/conditional/axios/feature-based/src/features/home/services/user.service.js +33 -0
  58. package/templates/conditional/axios/feature-based/src/features/home/services/user.service.ts +29 -0
  59. package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.client.js +24 -0
  60. package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.client.ts +24 -0
  61. package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.config.js +7 -0
  62. package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.config.ts +7 -0
  63. package/templates/conditional/axios/feature-based/src/shared/lib/axios/index.js +1 -0
  64. package/templates/conditional/axios/feature-based/src/shared/lib/axios/index.ts +1 -0
  65. package/templates/conditional/fetch/component-based/src/config/api.config.js +7 -0
  66. package/templates/conditional/fetch/component-based/src/config/api.config.ts +7 -0
  67. package/templates/conditional/fetch/component-based/src/services/api.client.js +51 -0
  68. package/templates/conditional/fetch/component-based/src/services/api.client.ts +55 -0
  69. package/templates/conditional/fetch/component-based/src/services/user.service.js +33 -0
  70. package/templates/conditional/fetch/component-based/src/services/user.service.ts +29 -0
  71. package/templates/conditional/fetch/feature-based/src/features/home/services/user.service.js +33 -0
  72. package/templates/conditional/fetch/feature-based/src/features/home/services/user.service.ts +29 -0
  73. package/templates/conditional/fetch/feature-based/src/shared/api/api.client.js +51 -0
  74. package/templates/conditional/fetch/feature-based/src/shared/api/api.client.ts +55 -0
  75. package/templates/conditional/fetch/feature-based/src/shared/api/api.config.js +7 -0
  76. package/templates/conditional/fetch/feature-based/src/shared/api/api.config.ts +7 -0
  77. package/templates/conditional/fetch/feature-based/src/shared/api/index.js +1 -0
  78. package/templates/conditional/fetch/feature-based/src/shared/api/index.ts +1 -0
  79. package/templates/conditional/formatter/oxfmt/.oxfmtrc.json +1 -1
  80. package/templates/conditional/formatter/prettier/.prettierrc +2 -2
  81. package/templates/conditional/icons/huge/component-based/bootstrap/src/pages/Home/Home.jsx +20 -0
  82. package/templates/conditional/icons/huge/component-based/bootstrap/src/pages/Home/Home.tsx +20 -0
  83. package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.jsx +26 -10
  84. package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.tsx +26 -10
  85. package/templates/conditional/icons/huge/component-based/tailwind/src/pages/Home/Home.jsx +20 -0
  86. package/templates/conditional/icons/huge/component-based/tailwind/src/pages/Home/Home.tsx +20 -0
  87. package/templates/conditional/icons/huge/feature-based/bootstrap/src/features/home/pages/HomePage.jsx +20 -0
  88. package/templates/conditional/icons/huge/feature-based/bootstrap/src/features/home/pages/HomePage.tsx +20 -0
  89. package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.jsx +27 -11
  90. package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.tsx +27 -11
  91. package/templates/conditional/icons/huge/feature-based/tailwind/src/features/home/pages/HomePage.jsx +20 -0
  92. package/templates/conditional/icons/huge/feature-based/tailwind/src/features/home/pages/HomePage.tsx +20 -0
  93. package/templates/conditional/icons/lucide/component-based/bootstrap/src/pages/Home/Home.jsx +19 -0
  94. package/templates/conditional/icons/lucide/component-based/bootstrap/src/pages/Home/Home.tsx +19 -0
  95. package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.jsx +25 -10
  96. package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.tsx +25 -10
  97. package/templates/conditional/icons/lucide/component-based/tailwind/src/pages/Home/Home.jsx +19 -0
  98. package/templates/conditional/icons/lucide/component-based/tailwind/src/pages/Home/Home.tsx +19 -0
  99. package/templates/conditional/icons/lucide/feature-based/bootstrap/src/features/home/pages/HomePage.jsx +19 -0
  100. package/templates/conditional/icons/lucide/feature-based/bootstrap/src/features/home/pages/HomePage.tsx +19 -0
  101. package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.jsx +26 -11
  102. package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.tsx +26 -11
  103. package/templates/conditional/icons/lucide/feature-based/tailwind/src/features/home/pages/HomePage.jsx +19 -0
  104. package/templates/conditional/icons/lucide/feature-based/tailwind/src/features/home/pages/HomePage.tsx +19 -0
  105. package/templates/conditional/linting/eslint/eslint.config.js +24 -2
  106. package/templates/conditional/linting/eslint/eslint.config.ts +25 -2
  107. package/templates/conditional/router/component-based/bootstrap/src/layouts/MainLayout.jsx +17 -0
  108. package/templates/conditional/router/component-based/bootstrap/src/layouts/MainLayout.tsx +17 -0
  109. package/templates/conditional/router/component-based/src/App.jsx +4 -5
  110. package/templates/conditional/router/component-based/src/App.tsx +4 -5
  111. package/templates/conditional/router/component-based/src/layouts/MainLayout.jsx +39 -0
  112. package/templates/conditional/router/component-based/src/layouts/MainLayout.tsx +39 -0
  113. package/templates/conditional/router/component-based/src/router/guards/AuthGuard.jsx +8 -0
  114. package/templates/conditional/router/component-based/src/router/guards/AuthGuard.tsx +14 -0
  115. package/templates/conditional/router/component-based/src/router/guards/GuestGuard.jsx +8 -0
  116. package/templates/conditional/router/component-based/src/router/guards/GuestGuard.tsx +14 -0
  117. package/templates/conditional/router/component-based/src/router/index.jsx +44 -0
  118. package/templates/conditional/router/component-based/src/router/index.tsx +44 -0
  119. package/templates/conditional/router/component-based/tailwind/src/layouts/MainLayout.jsx +17 -0
  120. package/templates/conditional/router/component-based/tailwind/src/layouts/MainLayout.tsx +17 -0
  121. package/templates/conditional/router/feature-based/bootstrap/src/shared/layouts/RootLayout.jsx +9 -0
  122. package/templates/conditional/router/feature-based/bootstrap/src/shared/layouts/RootLayout.tsx +9 -0
  123. package/templates/conditional/router/feature-based/src/app/App.jsx +6 -2
  124. package/templates/conditional/router/feature-based/src/app/App.tsx +6 -2
  125. package/templates/conditional/router/feature-based/src/app/router/guards/AuthGuard.jsx +8 -0
  126. package/templates/conditional/router/feature-based/src/app/router/guards/AuthGuard.tsx +14 -0
  127. package/templates/conditional/router/feature-based/src/app/router/guards/RoleGuard.jsx +8 -0
  128. package/templates/conditional/router/feature-based/src/app/router/guards/RoleGuard.tsx +15 -0
  129. package/templates/conditional/router/feature-based/src/app/router/index.jsx +16 -0
  130. package/templates/conditional/router/feature-based/src/app/router/index.tsx +16 -0
  131. package/templates/conditional/router/feature-based/src/app/router/routes/auth.routes.jsx +18 -0
  132. package/templates/conditional/router/feature-based/src/app/router/routes/auth.routes.tsx +18 -0
  133. package/templates/conditional/router/feature-based/src/app/router/routes/home.routes.jsx +8 -0
  134. package/templates/conditional/router/feature-based/src/app/router/routes/home.routes.tsx +8 -0
  135. package/templates/conditional/router/feature-based/src/shared/layouts/RootLayout.jsx +17 -0
  136. package/templates/conditional/router/feature-based/src/shared/layouts/RootLayout.tsx +17 -0
  137. package/templates/conditional/router/feature-based/tailwind/src/shared/layouts/RootLayout.jsx +9 -0
  138. package/templates/conditional/router/feature-based/tailwind/src/shared/layouts/RootLayout.tsx +9 -0
  139. package/templates/conditional/state/redux/component-based/src/pages/Home/counterSlice.ts +9 -3
  140. package/templates/conditional/state/redux/component-based/src/{context → providers}/StoreProvider.jsx +0 -1
  141. package/templates/conditional/state/redux/component-based/src/{context → providers}/StoreProvider.tsx +2 -2
  142. package/templates/conditional/state/redux/component-based/src/store/hooks.ts +4 -2
  143. package/templates/conditional/state/redux/component-based/src/store/index.ts +2 -2
  144. package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.jsx +1 -2
  145. package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.tsx +3 -3
  146. package/templates/conditional/state/redux/feature-based/src/features/home/store/counterSlice.ts +9 -3
  147. package/templates/conditional/state/redux/feature-based/src/shared/stores/hooks.ts +6 -0
  148. package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/index.ts +2 -2
  149. package/templates/conditional/state/zustand/component-based/src/store/useCounterStore.ts +8 -1
  150. package/templates/conditional/state/zustand/feature-based/src/stores/useCounterStore.ts +8 -1
  151. package/templates/conditional/testing/jest/babel.config.cjs +7 -0
  152. package/templates/conditional/testing/jest/component-based/src/__tests__/App.test.jsx +10 -0
  153. package/templates/conditional/testing/jest/component-based/src/__tests__/App.test.tsx +11 -0
  154. package/templates/conditional/testing/jest/{src → feature-based/src}/__tests__/App.test.jsx +2 -1
  155. package/templates/conditional/testing/jest/feature-based/src/__tests__/App.test.tsx +11 -0
  156. package/templates/conditional/testing/jest/jest.config.js +2 -3
  157. package/templates/conditional/testing/jest/jest.config.ts +6 -4
  158. package/templates/conditional/testing/jest/jest.setup.js +6 -0
  159. package/templates/conditional/testing/jest/jest.setup.ts +6 -0
  160. package/templates/conditional/testing/vitest/component-based/src/__tests__/App.test.jsx +10 -0
  161. package/templates/conditional/testing/{jest → vitest/component-based}/src/__tests__/App.test.tsx +2 -1
  162. package/templates/css/bootstrap/src/themes.css +14 -0
  163. package/templates/css/component-styles/bootstrap/component-based/src/components/common/Button.jsx +17 -0
  164. package/templates/css/component-styles/bootstrap/component-based/src/components/common/Button.tsx +22 -0
  165. package/templates/css/component-styles/bootstrap/component-based/src/layouts/MainLayout.jsx +15 -0
  166. package/templates/css/component-styles/bootstrap/component-based/src/layouts/MainLayout.tsx +19 -0
  167. package/templates/css/component-styles/bootstrap/component-based/src/pages/Home/Home.jsx +13 -0
  168. package/templates/css/component-styles/bootstrap/component-based/src/pages/Home/Home.tsx +13 -0
  169. package/templates/css/component-styles/bootstrap/feature-based/src/app/App.jsx +9 -0
  170. package/templates/css/component-styles/bootstrap/feature-based/src/app/App.tsx +9 -0
  171. package/templates/css/component-styles/bootstrap/feature-based/src/features/home/pages/HomePage.jsx +13 -0
  172. package/templates/css/component-styles/bootstrap/feature-based/src/features/home/pages/HomePage.tsx +13 -0
  173. package/templates/css/component-styles/bootstrap/feature-based/src/shared/components/ui/Button.jsx +17 -0
  174. package/templates/css/component-styles/bootstrap/feature-based/src/shared/components/ui/Button.tsx +22 -0
  175. package/templates/{architectures/feature-based/src/components/ui → css/component-styles/tailwind/component-based/src/components/common}/Button.jsx +1 -3
  176. package/templates/{architectures/feature-based/src/components/ui → css/component-styles/tailwind/component-based/src/components/common}/Button.tsx +1 -3
  177. package/templates/css/component-styles/tailwind/component-based/src/layouts/MainLayout.jsx +15 -0
  178. package/templates/css/component-styles/tailwind/component-based/src/layouts/MainLayout.tsx +19 -0
  179. package/templates/css/component-styles/tailwind/component-based/src/pages/Home/Home.jsx +13 -0
  180. package/templates/css/component-styles/tailwind/component-based/src/pages/Home/Home.tsx +13 -0
  181. package/templates/css/component-styles/tailwind/feature-based/src/app/App.jsx +9 -0
  182. package/templates/css/component-styles/tailwind/feature-based/src/app/App.tsx +9 -0
  183. package/templates/css/component-styles/tailwind/feature-based/src/features/home/pages/HomePage.jsx +13 -0
  184. package/templates/css/component-styles/tailwind/feature-based/src/features/home/pages/HomePage.tsx +13 -0
  185. package/templates/css/component-styles/tailwind/feature-based/src/shared/components/ui/Button.jsx +21 -0
  186. package/templates/css/component-styles/tailwind/feature-based/src/shared/components/ui/Button.tsx +26 -0
  187. package/templates/css/none/src/{index.css → main.css} +2 -0
  188. package/templates/css/none/src/themes.css +19 -0
  189. package/templates/css/tailwind/src/themes.css +9 -0
  190. package/templates/architectures/component-based/src/config/constants.js +0 -2
  191. package/templates/architectures/component-based/src/config/constants.ts +0 -2
  192. package/templates/architectures/component-based/src/config/routes.js +0 -7
  193. package/templates/architectures/component-based/src/config/routes.ts +0 -7
  194. package/templates/architectures/component-based/src/context/AppContext.jsx +0 -13
  195. package/templates/architectures/component-based/src/context/AppContext.tsx +0 -13
  196. package/templates/architectures/component-based/src/hooks/index.js +0 -1
  197. package/templates/architectures/component-based/src/hooks/index.ts +0 -1
  198. package/templates/architectures/component-based/src/layouts/index.js +0 -1
  199. package/templates/architectures/component-based/src/layouts/index.ts +0 -1
  200. package/templates/architectures/component-based/src/routes/index.jsx +0 -11
  201. package/templates/architectures/component-based/src/routes/index.tsx +0 -11
  202. package/templates/architectures/component-based/src/styles/globals.css +0 -7
  203. package/templates/architectures/component-based/src/utils/index.js +0 -1
  204. package/templates/architectures/component-based/src/utils/index.ts +0 -1
  205. package/templates/architectures/feature-based/src/config/constants.js +0 -2
  206. package/templates/architectures/feature-based/src/config/constants.ts +0 -2
  207. package/templates/architectures/feature-based/src/hooks/index.js +0 -1
  208. package/templates/architectures/feature-based/src/hooks/index.ts +0 -1
  209. package/templates/architectures/feature-based/src/utils/cn.ts +0 -6
  210. package/templates/architectures/feature-based/src/utils/index.js +0 -1
  211. package/templates/architectures/feature-based/src/utils/index.ts +0 -1
  212. package/templates/conditional/axios/component-based/src/services/axios.jsx +0 -19
  213. package/templates/conditional/axios/component-based/src/services/axios.ts +0 -19
  214. package/templates/conditional/axios/component-based/src/services/index.js +0 -1
  215. package/templates/conditional/axios/component-based/src/services/index.ts +0 -1
  216. package/templates/conditional/axios/feature-based/src/lib/axios.jsx +0 -19
  217. package/templates/conditional/axios/feature-based/src/lib/axios.ts +0 -19
  218. package/templates/conditional/axios/feature-based/src/lib/index.js +0 -1
  219. package/templates/conditional/axios/feature-based/src/lib/index.ts +0 -1
  220. package/templates/conditional/fetch/component-based/src/services/api.jsx +0 -27
  221. package/templates/conditional/fetch/component-based/src/services/api.ts +0 -27
  222. package/templates/conditional/fetch/component-based/src/services/index.js +0 -1
  223. package/templates/conditional/fetch/component-based/src/services/index.ts +0 -1
  224. package/templates/conditional/fetch/feature-based/src/lib/api.jsx +0 -27
  225. package/templates/conditional/fetch/feature-based/src/lib/api.ts +0 -27
  226. package/templates/conditional/fetch/feature-based/src/lib/index.js +0 -1
  227. package/templates/conditional/fetch/feature-based/src/lib/index.ts +0 -1
  228. package/templates/conditional/router/component-based/src/routes/index.jsx +0 -13
  229. package/templates/conditional/router/component-based/src/routes/index.tsx +0 -13
  230. package/templates/conditional/router/feature-based/src/app/router.jsx +0 -13
  231. package/templates/conditional/router/feature-based/src/app/router.tsx +0 -13
  232. package/templates/conditional/state/redux/feature-based/src/stores/hooks.ts +0 -4
  233. package/templates/css/tailwind/src/index.css +0 -1
  234. /package/templates/architectures/component-based/src/{components/layout → config}/.gitkeep +0 -0
  235. /package/templates/architectures/{feature-based/src/features/home/interfaces → component-based/src/providers}/.gitkeep +0 -0
  236. /package/templates/architectures/{feature-based/src/lib → component-based/src/styles}/.gitkeep +0 -0
  237. /package/templates/architectures/feature-based/src/{stores → features/home/types}/.gitkeep +0 -0
  238. /package/templates/architectures/feature-based/src/{components → shared/components}/ui/index.js +0 -0
  239. /package/templates/architectures/feature-based/src/{components → shared/components}/ui/index.ts +0 -0
  240. /package/templates/architectures/feature-based/src/{hooks → shared/hooks}/useLocalStorage.jsx +0 -0
  241. /package/templates/architectures/feature-based/src/{utils → shared/utils}/cn.jsx +0 -0
  242. /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/hooks.js +0 -0
  243. /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/index.js +0 -0
  244. /package/templates/conditional/testing/vitest/{src → feature-based/src}/__tests__/App.test.jsx +0 -0
  245. /package/templates/conditional/testing/vitest/{src → feature-based/src}/__tests__/App.test.tsx +0 -0
  246. /package/templates/css/bootstrap/src/{index.css → globals.css} +0 -0
  247. /package/templates/{architectures/feature-based/src/styles → css/tailwind/src}/globals.css +0 -0
package/README.md CHANGED
@@ -17,9 +17,9 @@ npm run dev
17
17
  Non-interactive Quick Setup (TypeScript + Tailwind + Feature-based + Router + ESLint + Prettier + Vitest), no prompts:
18
18
 
19
19
  ```bash
20
- npm create lumen my-app -y
20
+ npm create lumen my-app -- -y
21
21
  # or
22
- npm create lumen -y my-app
22
+ npm create lumen -- -y my-app
23
23
  ```
24
24
 
25
25
  The CLI ignores flag arguments when resolving the project name, so `-y` can appear before or after the app name without being mistaken for the folder name.
@@ -87,36 +87,40 @@ Feature-based (example):
87
87
 
88
88
  ```
89
89
  src/
90
- ├── app
90
+ ├── app # App shell and global providers
91
91
  │   ├── App.tsx
92
+ │   ├── contexts
93
+ │   │   └── themecontext.ts # createContext + ThemeContextValue
92
94
  │   ├── providers
93
- │   │   └── ThemeProvider.tsx
94
- │   └── router.tsx
95
- ├── components
96
- │   └── ui
97
- ├── config
98
- │   └── constants.ts
99
- ├── features
100
- │   └── logout
95
+ │   │   └── ThemeProvider.tsx # Provider component
96
+ │   ├── hooks
97
+ │   │   └── useTheme.ts # Hook that reads ThemeContext
98
+ │   └── router # Data router (per feature area)
99
+ │   ├── guards # AuthGuard, RoleGuard
100
+ │   ├── routes # home.routes, auth.routes
101
+ │   └── index.tsx # createBrowserRouter init
102
+ ├── features # Feature modules (business logic owned per feature)
103
+ │   └── home
101
104
  │   ├── components
102
- │   ├── interfaces
105
+ │   ├── hooks
106
+ │   ├── index.ts # public feature barrel
103
107
  │   ├── layouts
104
108
  │   ├── pages
105
109
  │   ├── services
106
- │   └── store
107
- ├── hooks
108
- │   ├── index.ts
109
- │   └── useLocalStorage.ts
110
- ├── index.css
111
- ├── lib
112
- ├── main.tsx
113
- ├── stores
114
- ├── styles
115
- │   └── globals.css
116
- ├── test
117
- │   └── setup.ts
118
- ├── types
119
- └── utils
110
+ │   ├── store
111
+ │   └── types
112
+ └── shared # Reusable, business-agnostic resources
113
+ ├── api/lib # fetch client → api/; axios init → lib/axios/ (per choice)
114
+ ├── components
115
+ │   └── ui
116
+ ├── hooks
117
+ ├── layouts
118
+ ├── stores
119
+ ├── styles
120
+ │   ├── globals.css # Tailwind/Bootstrap directives (or main.css for vanilla)
121
+ │   └── themes.css # Theme tokens (Tailwind @theme / Bootstrap data-bs-theme / CSS vars)
122
+ ├── types
123
+ └── utils
120
124
  ```
121
125
 
122
126
  Component-based (example):
@@ -126,28 +130,32 @@ src/
126
130
  ├── App.tsx
127
131
  ├── components
128
132
  │   ├── common
129
- │   ├── form
130
- │   └── layout
131
- ├── config
132
- │   ├── constants.ts
133
- │   └── routes.ts
134
- ├── context
133
+ │   └── form
134
+ ├── config # API config (when an axios/fetch client is chosen)
135
135
  ├── hooks
136
- ├── index.css
137
136
  ├── layouts
138
137
  ├── main.tsx
139
138
  ├── pages
140
- ├── routes
139
+ ├── providers # Provider components (createContext + Provider in separate files inside providers/)
140
+ │   ├── appcontext.ts # createContext + AppContextValue
141
+ │   └── AppProvider.tsx # Provider component
142
+ ├── hooks
143
+ │   └── useApp.ts # Hook that reads AppContext
144
+ ├── router # Centralized data router
145
+ │   ├── guards # AuthGuard, GuestGuard
146
+ │   └── index.tsx # Single source of truth for all routes
141
147
  ├── services
142
148
  ├── store
143
149
  ├── styles
150
+ │   ├── globals.css # Tailwind/Bootstrap directives (or main.css for vanilla)
151
+ │   └── themes.css # Theme tokens (Tailwind @theme / Bootstrap data-bs-theme / CSS vars)
144
152
  ├── test
145
153
  └── utils
146
154
  ```
147
155
 
148
156
  ## Roadmap
149
157
 
150
- See `docs/ROADMAP.md` for planned features and upcoming releases.
158
+ Released versions live in [`docs/CHANGELOG.md`](./docs/CHANGELOG.md); planned work is tracked in [`docs/ROADMAP.md`](./docs/ROADMAP.md).
151
159
 
152
160
  ## Requirements
153
161
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-lumen",
3
- "version": "1.1.3",
3
+ "version": "1.2.0-beta.1",
4
4
  "description": "Scaffold a React + Vite project with architecture choice: feature-based or component-based.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,7 +15,13 @@
15
15
  "LICENSE"
16
16
  ],
17
17
  "scripts": {
18
- "test": "node --import ./register.js --test \"tests/unit/*.test.mjs\" \"tests/smoke/*.test.mjs\""
18
+ "test": "node --import ./register.js --test \"tests/unit/*.test.mjs\" \"tests/smoke/*.test.mjs\"",
19
+ "verify:vendor": "node --import ./register.js tests/verify/install-vendor.mjs",
20
+ "verify:offline": "node --import ./register.js tests/verify/verify-offline.mjs",
21
+ "verify:installed": "node --import ./register.js tests/verify/verify-installed.mjs",
22
+ "verify": "npm run verify:vendor && npm run verify:offline",
23
+ "verify:full": "npm run verify:vendor && npm run verify:offline && npm run verify:installed",
24
+ "verify:matrix": "FULL=1 npm run verify:offline"
19
25
  },
20
26
  "keywords": [
21
27
  "scaffold",
package/src/configure.js CHANGED
@@ -19,7 +19,7 @@ export async function configureProject(projectPath, language, cssFramework) {
19
19
  }
20
20
 
21
21
  // Add scripts to package.json
22
- await configurePackageJson(projectPath);
22
+ await configurePackageJson(projectPath, language);
23
23
  }
24
24
 
25
25
  async function configureTsconfig(projectPath) {
@@ -31,8 +31,13 @@ async function configureTsconfig(projectPath) {
31
31
  const config = JSON.parse(content);
32
32
 
33
33
  if (!config.compilerOptions) config.compilerOptions = {};
34
- config.compilerOptions.baseUrl = ".";
34
+ config.compilerOptions.strict = true;
35
35
  config.compilerOptions.paths = paths;
36
+ if (config.compilerOptions.types?.length && !config.compilerOptions.types.includes("vite/client")) {
37
+ config.compilerOptions.types.push("vite/client");
38
+ } else if (!config.compilerOptions.types) {
39
+ config.compilerOptions.types = ["vite/client"];
40
+ }
36
41
 
37
42
  await fsp.writeFile(
38
43
  tsconfigAppPath,
@@ -58,7 +63,7 @@ async function configureTsconfig(projectPath) {
58
63
  noUnusedLocals: true,
59
64
  noUnusedParameters: true,
60
65
  noFallthroughCasesInSwitch: true,
61
- baseUrl: ".",
66
+ types: ["vite/client"],
62
67
  paths,
63
68
  },
64
69
  include: ["src"],
@@ -70,11 +75,19 @@ async function configureTsconfig(projectPath) {
70
75
  );
71
76
  }
72
77
 
73
- // Create/update root tsconfig.json with references
78
+ // Create/update root tsconfig.json with references.
79
+ // Preserve the ./tsconfig.node.json reference (Vite config) when present.
74
80
  const rootTsconfigPath = path.join(projectPath, "tsconfig.json");
81
+ const nodeConfigPath = path.join(projectPath, "tsconfig.node.json");
82
+ const references = [{ path: "./tsconfig.app.json" }];
83
+ try {
84
+ await fsp.access(nodeConfigPath);
85
+ references.push({ path: "./tsconfig.node.json" });
86
+ } catch {}
87
+
75
88
  const rootTsconfig = {
76
89
  files: [],
77
- references: [{ path: "./tsconfig.app.json" }],
90
+ references,
78
91
  };
79
92
  await fsp.writeFile(
80
93
  rootTsconfigPath,
@@ -100,7 +113,7 @@ async function addPathAliasesToViteConfig(projectPath, ext) {
100
113
  try {
101
114
  let content = await readFileContent(viteConfigPath);
102
115
 
103
- if (content.includes("tsconfigPaths")) return;
116
+ if (content.includes("find: '@'")) return;
104
117
 
105
118
  const lines = content.split("\n");
106
119
 
@@ -112,8 +125,8 @@ async function addPathAliasesToViteConfig(projectPath, ext) {
112
125
 
113
126
  // Insert path/fileURLToPath imports after last import
114
127
  const newImports = [
115
- 'import path from "path";',
116
- 'import { fileURLToPath } from "url";',
128
+ "import path from 'path';",
129
+ "import { fileURLToPath } from 'url';",
117
130
  "const __dirname = path.dirname(fileURLToPath(import.meta.url));",
118
131
  ];
119
132
  lines.splice(lastImportIdx + 1, 0, ...newImports);
@@ -121,13 +134,10 @@ async function addPathAliasesToViteConfig(projectPath, ext) {
121
134
  let result = lines.join("\n");
122
135
 
123
136
  const aliasArray = getViteAliases()
124
- .map(
125
- (a) =>
126
- `{ find: "${a.find}", replacement: ${a.replacement} }`
127
- )
128
- .join(",\n ");
137
+ .map((a) => `{ find: '${a.find}', replacement: ${a.replacement} }`)
138
+ .join(",\n ");
129
139
 
130
- const resolveBlock = `resolve: {\n tsconfigPaths: true,\n alias: [\n ${aliasArray}\n ],\n }`;
140
+ const resolveBlock = `resolve: {\n alias: [\n ${aliasArray},\n ],\n }`;
131
141
 
132
142
  if (result.includes("resolve:")) {
133
143
  result = result.replace(/resolve:\s*\{/, resolveBlock);
@@ -144,7 +154,7 @@ async function addPathAliasesToViteConfig(projectPath, ext) {
144
154
  }
145
155
  }
146
156
 
147
- async function configurePackageJson(projectPath) {
157
+ async function configurePackageJson(projectPath, language) {
148
158
  const pkgPath = path.join(projectPath, "package.json");
149
159
  try {
150
160
  const content = await readFileContent(pkgPath);
@@ -156,6 +166,10 @@ async function configurePackageJson(projectPath) {
156
166
  pkg.scripts.build = "vite build";
157
167
  pkg.scripts.preview = "vite preview";
158
168
 
169
+ if (language === "ts") {
170
+ pkg.scripts.typecheck = "tsc -b";
171
+ }
172
+
159
173
  await fsp.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
160
174
  } catch {
161
175
  // file doesn't exist, skip
package/src/css.js CHANGED
@@ -1,4 +1,3 @@
1
- import fs from "fs";
2
1
  import { promises as fsp } from "fs";
3
2
  import path from "path";
4
3
  import { deleteIfExists } from "@/utils/fs.js";
@@ -8,12 +7,28 @@ export async function setupCssFramework({
8
7
  templatesDir,
9
8
  language,
10
9
  cssFramework,
10
+ architecture,
11
11
  ext,
12
12
  pkg,
13
13
  }) {
14
14
  process.chdir(projectPath);
15
15
  const cssDir = path.join(templatesDir, "css");
16
- const indexCssPath = path.join(projectPath, "src", "index.css");
16
+ // Feature-based main.* imports ./shared/styles/globals.css (or main.css when
17
+ // framework is "none"); component-based imports ./styles/globals.css (or
18
+ // main.css). The chosen framework's styles land in the file the architecture
19
+ // actually imports.
20
+ const stylesDir =
21
+ architecture === "feature-based"
22
+ ? path.join(projectPath, "src", "shared", "styles")
23
+ : path.join(projectPath, "src", "styles");
24
+
25
+ // Vanilla CSS gets a stylesheet named main.css; tailwind/bootstrap keep
26
+ // globals.css (their idiomatic name — they inject framework directives).
27
+ const mainFileName = cssFramework === "none" ? "main.css" : "globals.css";
28
+
29
+ async function writeCss(content, fileName) {
30
+ await fsp.writeFile(path.join(stylesDir, fileName), content, "utf8");
31
+ }
17
32
 
18
33
  if (cssFramework === "tailwind") {
19
34
  const viteConfigFile = `vite.config.${language === "ts" ? "ts" : "js"}`;
@@ -24,14 +39,19 @@ export async function setupCssFramework({
24
39
  );
25
40
  await fsp.writeFile(viteConfigTarget, viteConfigContent, "utf8");
26
41
 
27
- const indexCssContent = await fsp.readFile(
28
- path.join(cssDir, "tailwind", "src", "index.css"),
42
+ const globalsContent = await fsp.readFile(
43
+ path.join(cssDir, "tailwind", "src", "globals.css"),
29
44
  "utf8"
30
45
  );
31
- await fsp.writeFile(indexCssPath, indexCssContent, "utf8");
46
+ const themesContent = await fsp.readFile(
47
+ path.join(cssDir, "tailwind", "src", "themes.css"),
48
+ "utf8"
49
+ );
50
+ await writeCss(globalsContent, "globals.css");
51
+ await writeCss(themesContent, "themes.css");
32
52
  } else if (cssFramework === "bootstrap") {
33
53
  const mainFile = path.join(projectPath, "src", `main.${ext}`);
34
- if (fs.existsSync(mainFile)) {
54
+ try {
35
55
  let mainContent = await fsp.readFile(mainFile, "utf8");
36
56
  if (
37
57
  !mainContent.includes("bootstrap/dist/css/bootstrap.min.css")
@@ -40,20 +60,59 @@ export async function setupCssFramework({
40
60
  "import 'bootstrap/dist/css/bootstrap.min.css';\n" + mainContent;
41
61
  await fsp.writeFile(mainFile, mainContent, "utf8");
42
62
  }
43
- }
44
- const indexCssContent = await fsp.readFile(
45
- path.join(cssDir, "bootstrap", "src", "index.css"),
63
+ } catch {}
64
+
65
+ const globalsContent = await fsp.readFile(
66
+ path.join(cssDir, "bootstrap", "src", "globals.css"),
67
+ "utf8"
68
+ );
69
+ const themesContent = await fsp.readFile(
70
+ path.join(cssDir, "bootstrap", "src", "themes.css"),
46
71
  "utf8"
47
72
  );
48
- await fsp.writeFile(indexCssPath, indexCssContent, "utf8");
73
+ await writeCss(globalsContent, "globals.css");
74
+ await writeCss(themesContent, "themes.css");
49
75
  } else {
50
- const indexCssContent = await fsp.readFile(
51
- path.join(cssDir, "none", "src", "index.css"),
76
+ const mainContent = await fsp.readFile(
77
+ path.join(cssDir, "none", "src", "main.css"),
78
+ "utf8"
79
+ );
80
+ const themesContent = await fsp.readFile(
81
+ path.join(cssDir, "none", "src", "themes.css"),
52
82
  "utf8"
53
83
  );
54
- await fsp.writeFile(indexCssPath, indexCssContent, "utf8");
84
+ await writeCss(mainContent, "main.css");
85
+ await writeCss(themesContent, "themes.css");
55
86
  }
56
87
 
57
- // Clean up Vite's default App.css
88
+ // Ensure main.{ext} imports the correct stylesheet name for this framework.
89
+ await syncMainCssImport(projectPath, ext, architecture, mainFileName);
90
+
91
+ // Ensure the styles dir exists (for the .gitkeep placeholder when no real
92
+ // file lives there yet — pruneRedundantGitkeeps removes it after overlays).
93
+ await fsp.mkdir(stylesDir, { recursive: true });
94
+
95
+ // Clean up Vite's default CSS files; src/index.css is the framework-agnostic
96
+ // leftover Vite scaffolds and is never imported in our generated projects.
58
97
  await deleteIfExists(path.join(projectPath, "src", "App.css"));
98
+ await deleteIfExists(path.join(projectPath, "src", "index.css"));
99
+ }
100
+
101
+ // Rewrite the CSS import in main.{ext} so it matches the file the framework
102
+ // actually wrote (main.css for "none", globals.css for tailwind/bootstrap).
103
+ async function syncMainCssImport(projectPath, ext, architecture, mainFileName) {
104
+ const mainPath = path.join(projectPath, "src", `main.${ext}`);
105
+ try {
106
+ let content = await fsp.readFile(mainPath, "utf8");
107
+ const expected =
108
+ architecture === "feature-based"
109
+ ? `./shared/styles/${mainFileName}`
110
+ : `./styles/${mainFileName}`;
111
+ const wrong =
112
+ architecture === "feature-based"
113
+ ? /import ['"]\.\/shared\/styles\/(globals|main)\.css['"]/
114
+ : /import ['"]\.\/styles\/(globals|main)\.css['"]/;
115
+ content = content.replace(wrong, `import '${expected}'`);
116
+ await fsp.writeFile(mainPath, content, "utf8");
117
+ } catch {}
59
118
  }
@@ -71,11 +71,14 @@ export async function installAllDeps(responses, pkg, cwd) {
71
71
  } else if (responses.testing === "jest") {
72
72
  devDeps.push(
73
73
  "jest",
74
- "ts-jest",
75
- "@types/jest",
74
+ "jest-environment-jsdom",
76
75
  "@testing-library/react",
77
76
  "@testing-library/jest-dom",
78
- "jsdom"
77
+ "jsdom",
78
+ "babel-jest",
79
+ "@babel/preset-env",
80
+ "@babel/preset-react",
81
+ "@babel/preset-typescript"
79
82
  );
80
83
  }
81
84
 
@@ -84,6 +87,8 @@ export async function installAllDeps(responses, pkg, cwd) {
84
87
  devDeps.push("eslint", "@eslint/js", "eslint-plugin-react-hooks", "eslint-plugin-react-refresh", "globals");
85
88
  if (responses.language === "ts") {
86
89
  devDeps.push("typescript-eslint");
90
+ // ESLint >= 10 loads TS config files (eslint.config.ts) via jiti.
91
+ devDeps.push("jiti");
87
92
  }
88
93
  } else if (responses.linter === "oxlint") {
89
94
  devDeps.push("oxlint");
package/src/format.js ADDED
@@ -0,0 +1,28 @@
1
+ import path from "path";
2
+ import { execa } from "execa";
3
+ import { promises as fsp } from "fs";
4
+
5
+ async function exists(p) {
6
+ try {
7
+ await fsp.access(p);
8
+ return true;
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
13
+
14
+ // Runs the project-local formatter (installed as a devDependency) so a freshly
15
+ // generated project is canonical under its chosen formatter by construction.
16
+ // Falls back to the bare command name so the same helper works when the binary
17
+ // is already on PATH (e.g. verification harnesses resolving from a vendored
18
+ // node_modules symlink).
19
+ export async function runProjectFormat(projectPath, responses) {
20
+ if (!responses.formatter || responses.formatter === "none") return;
21
+
22
+ const formatter = responses.formatter;
23
+ const bin = path.join(projectPath, "node_modules", ".bin", formatter);
24
+ const command = (await exists(bin)) ? bin : formatter;
25
+ const args = formatter === "prettier" ? ["--write", "."] : ["."];
26
+
27
+ await execa(command, args, { cwd: projectPath, stdio: "pipe" });
28
+ }