create-lumen 1.1.4 → 1.2.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.
- package/README.md +41 -34
- package/package.json +5 -1
- package/src/configure.js +6 -2
- package/src/css.js +71 -24
- package/src/dependencies.js +15 -6
- package/src/injector.js +116 -24
- package/src/main.js +3 -1
- package/src/readme.js +64 -22
- package/templates/architectures/component-based/src/App.jsx +6 -3
- package/templates/architectures/component-based/src/App.tsx +6 -3
- package/templates/architectures/component-based/src/components/common/Button.jsx +5 -2
- package/templates/architectures/component-based/src/components/common/Button.tsx +5 -2
- package/templates/architectures/component-based/src/hooks/useApp.js +10 -0
- package/templates/architectures/component-based/src/hooks/useApp.ts +10 -0
- package/templates/architectures/component-based/src/layouts/MainLayout.jsx +12 -4
- package/templates/architectures/component-based/src/layouts/MainLayout.tsx +12 -4
- package/templates/architectures/component-based/src/pages/Home/Home.jsx +6 -1
- package/templates/architectures/component-based/src/pages/Home/Home.tsx +6 -1
- package/templates/architectures/component-based/src/providers/AppProvider.jsx +20 -0
- package/templates/architectures/component-based/src/providers/AppProvider.tsx +24 -0
- package/templates/architectures/component-based/src/providers/appcontext.js +3 -0
- package/templates/architectures/component-based/src/{context/app-context.ts → providers/appcontext.ts} +1 -3
- package/templates/architectures/{feature-based → component-based}/src/types/index.js +7 -0
- package/templates/architectures/{feature-based → component-based}/src/types/index.ts +5 -0
- package/templates/architectures/feature-based/main.jsx +1 -1
- package/templates/architectures/feature-based/main.tsx +1 -1
- package/templates/architectures/feature-based/scripts/create-feature.mjs +2 -2
- package/templates/architectures/feature-based/src/app/App.jsx +15 -4
- package/templates/architectures/feature-based/src/app/App.tsx +15 -4
- package/templates/architectures/feature-based/src/app/contexts/themecontext.js +3 -0
- package/templates/architectures/feature-based/src/app/contexts/themecontext.ts +8 -0
- package/templates/architectures/feature-based/src/app/hooks/useTheme.js +10 -0
- package/templates/architectures/feature-based/src/app/hooks/useTheme.ts +10 -0
- package/templates/architectures/feature-based/src/app/providers/ThemeProvider.jsx +18 -1
- package/templates/architectures/feature-based/src/app/providers/ThemeProvider.tsx +19 -2
- package/templates/architectures/feature-based/src/features/home/pages/HomePage.jsx +18 -4
- package/templates/architectures/feature-based/src/features/home/pages/HomePage.tsx +18 -4
- package/templates/architectures/feature-based/src/shared/components/ui/Button.jsx +31 -0
- package/templates/architectures/feature-based/src/shared/components/ui/Button.tsx +36 -0
- package/templates/architectures/feature-based/src/shared/layouts/.gitkeep +0 -0
- package/templates/architectures/feature-based/src/shared/stores/.gitkeep +0 -0
- package/templates/architectures/feature-based/src/shared/styles/.gitkeep +0 -0
- package/templates/architectures/feature-based/src/shared/types/index.js +20 -0
- package/templates/architectures/feature-based/src/shared/types/index.ts +16 -0
- package/templates/conditional/axios/component-based/src/config/axios.config.js +7 -0
- package/templates/conditional/axios/component-based/src/config/axios.config.ts +7 -0
- package/templates/conditional/axios/component-based/src/services/axios.client.js +24 -0
- package/templates/conditional/axios/component-based/src/services/axios.client.ts +24 -0
- package/templates/conditional/axios/component-based/src/services/user.service.js +33 -0
- package/templates/conditional/axios/component-based/src/services/user.service.ts +29 -0
- package/templates/conditional/axios/feature-based/src/features/home/services/user.service.js +33 -0
- package/templates/conditional/axios/feature-based/src/features/home/services/user.service.ts +29 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.client.js +24 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.client.ts +24 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.config.js +7 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.config.ts +7 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/index.js +1 -0
- package/templates/conditional/axios/feature-based/src/shared/lib/axios/index.ts +1 -0
- package/templates/conditional/fetch/component-based/src/config/api.config.js +7 -0
- package/templates/conditional/fetch/component-based/src/config/api.config.ts +7 -0
- package/templates/conditional/fetch/component-based/src/services/api.client.js +51 -0
- package/templates/conditional/fetch/component-based/src/services/api.client.ts +55 -0
- package/templates/conditional/fetch/component-based/src/services/user.service.js +33 -0
- package/templates/conditional/fetch/component-based/src/services/user.service.ts +29 -0
- package/templates/conditional/fetch/feature-based/src/features/home/services/user.service.js +33 -0
- package/templates/conditional/fetch/feature-based/src/features/home/services/user.service.ts +29 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/api.client.js +51 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/api.client.ts +55 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/api.config.js +7 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/api.config.ts +7 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/index.js +1 -0
- package/templates/conditional/fetch/feature-based/src/shared/api/index.ts +1 -0
- package/templates/conditional/icons/huge/component-based/bootstrap/src/pages/Home/Home.jsx +20 -0
- package/templates/conditional/icons/huge/component-based/bootstrap/src/pages/Home/Home.tsx +20 -0
- package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.jsx +24 -8
- package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.tsx +24 -8
- package/templates/conditional/icons/huge/component-based/tailwind/src/pages/Home/Home.jsx +20 -0
- package/templates/conditional/icons/huge/component-based/tailwind/src/pages/Home/Home.tsx +20 -0
- package/templates/conditional/icons/huge/feature-based/bootstrap/src/features/home/pages/HomePage.jsx +20 -0
- package/templates/conditional/icons/huge/feature-based/bootstrap/src/features/home/pages/HomePage.tsx +20 -0
- package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.jsx +25 -9
- package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.tsx +25 -9
- package/templates/conditional/icons/huge/feature-based/tailwind/src/features/home/pages/HomePage.jsx +20 -0
- package/templates/conditional/icons/huge/feature-based/tailwind/src/features/home/pages/HomePage.tsx +20 -0
- package/templates/conditional/icons/lucide/component-based/bootstrap/src/pages/Home/Home.jsx +19 -0
- package/templates/conditional/icons/lucide/component-based/bootstrap/src/pages/Home/Home.tsx +19 -0
- package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.jsx +24 -8
- package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.tsx +24 -8
- package/templates/conditional/icons/lucide/component-based/tailwind/src/pages/Home/Home.jsx +19 -0
- package/templates/conditional/icons/lucide/component-based/tailwind/src/pages/Home/Home.tsx +19 -0
- package/templates/conditional/icons/lucide/feature-based/bootstrap/src/features/home/pages/HomePage.jsx +19 -0
- package/templates/conditional/icons/lucide/feature-based/bootstrap/src/features/home/pages/HomePage.tsx +19 -0
- package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.jsx +25 -9
- package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.tsx +25 -9
- package/templates/conditional/icons/lucide/feature-based/tailwind/src/features/home/pages/HomePage.jsx +19 -0
- package/templates/conditional/icons/lucide/feature-based/tailwind/src/features/home/pages/HomePage.tsx +19 -0
- package/templates/conditional/router/component-based/bootstrap/src/layouts/MainLayout.jsx +17 -0
- package/templates/conditional/router/component-based/bootstrap/src/layouts/MainLayout.tsx +17 -0
- package/templates/conditional/router/component-based/src/App.jsx +4 -4
- package/templates/conditional/router/component-based/src/App.tsx +4 -4
- package/templates/conditional/router/component-based/src/layouts/MainLayout.jsx +39 -0
- package/templates/conditional/router/component-based/src/layouts/MainLayout.tsx +39 -0
- package/templates/conditional/router/component-based/src/router/guards/AuthGuard.jsx +8 -0
- package/templates/conditional/router/component-based/src/router/guards/AuthGuard.tsx +14 -0
- package/templates/conditional/router/component-based/src/router/guards/GuestGuard.jsx +8 -0
- package/templates/conditional/router/component-based/src/router/guards/GuestGuard.tsx +14 -0
- package/templates/conditional/router/component-based/src/router/index.jsx +44 -0
- package/templates/conditional/router/component-based/src/router/index.tsx +44 -0
- package/templates/conditional/router/component-based/tailwind/src/layouts/MainLayout.jsx +17 -0
- package/templates/conditional/router/component-based/tailwind/src/layouts/MainLayout.tsx +17 -0
- package/templates/conditional/router/feature-based/bootstrap/src/shared/layouts/RootLayout.jsx +9 -0
- package/templates/conditional/router/feature-based/bootstrap/src/shared/layouts/RootLayout.tsx +9 -0
- package/templates/conditional/router/feature-based/src/app/App.jsx +6 -1
- package/templates/conditional/router/feature-based/src/app/App.tsx +6 -1
- package/templates/conditional/router/feature-based/src/app/router/guards/AuthGuard.jsx +8 -0
- package/templates/conditional/router/feature-based/src/app/router/guards/AuthGuard.tsx +14 -0
- package/templates/conditional/router/feature-based/src/app/router/guards/RoleGuard.jsx +8 -0
- package/templates/conditional/router/feature-based/src/app/router/guards/RoleGuard.tsx +15 -0
- package/templates/conditional/router/feature-based/src/app/router/index.jsx +16 -0
- package/templates/conditional/router/feature-based/src/app/router/index.tsx +16 -0
- package/templates/conditional/router/feature-based/src/app/router/routes/auth.routes.jsx +18 -0
- package/templates/conditional/router/feature-based/src/app/router/routes/auth.routes.tsx +18 -0
- package/templates/conditional/router/feature-based/src/app/router/routes/home.routes.jsx +8 -0
- package/templates/conditional/router/feature-based/src/app/router/routes/home.routes.tsx +8 -0
- package/templates/conditional/router/feature-based/src/shared/layouts/RootLayout.jsx +17 -0
- package/templates/conditional/router/feature-based/src/shared/layouts/RootLayout.tsx +17 -0
- package/templates/conditional/router/feature-based/tailwind/src/shared/layouts/RootLayout.jsx +9 -0
- package/templates/conditional/router/feature-based/tailwind/src/shared/layouts/RootLayout.tsx +9 -0
- package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.jsx +1 -1
- package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.tsx +1 -1
- package/templates/css/bootstrap/src/themes.css +14 -0
- package/templates/css/component-styles/bootstrap/component-based/src/components/common/Button.jsx +17 -0
- package/templates/css/component-styles/bootstrap/component-based/src/components/common/Button.tsx +22 -0
- package/templates/css/component-styles/bootstrap/component-based/src/layouts/MainLayout.jsx +15 -0
- package/templates/css/component-styles/bootstrap/component-based/src/layouts/MainLayout.tsx +19 -0
- package/templates/css/component-styles/bootstrap/component-based/src/pages/Home/Home.jsx +13 -0
- package/templates/css/component-styles/bootstrap/component-based/src/pages/Home/Home.tsx +13 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/app/App.jsx +9 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/app/App.tsx +9 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/features/home/pages/HomePage.jsx +13 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/features/home/pages/HomePage.tsx +13 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/shared/components/ui/Button.jsx +17 -0
- package/templates/css/component-styles/bootstrap/feature-based/src/shared/components/ui/Button.tsx +22 -0
- package/templates/{architectures/feature-based/src/components/ui → css/component-styles/tailwind/component-based/src/components/common}/Button.jsx +1 -1
- package/templates/{architectures/feature-based/src/components/ui → css/component-styles/tailwind/component-based/src/components/common}/Button.tsx +1 -1
- package/templates/css/component-styles/tailwind/component-based/src/layouts/MainLayout.jsx +15 -0
- package/templates/css/component-styles/tailwind/component-based/src/layouts/MainLayout.tsx +19 -0
- package/templates/css/component-styles/tailwind/component-based/src/pages/Home/Home.jsx +13 -0
- package/templates/css/component-styles/tailwind/component-based/src/pages/Home/Home.tsx +13 -0
- package/templates/css/component-styles/tailwind/feature-based/src/app/App.jsx +9 -0
- package/templates/css/component-styles/tailwind/feature-based/src/app/App.tsx +9 -0
- package/templates/css/component-styles/tailwind/feature-based/src/features/home/pages/HomePage.jsx +13 -0
- package/templates/css/component-styles/tailwind/feature-based/src/features/home/pages/HomePage.tsx +13 -0
- package/templates/css/component-styles/tailwind/feature-based/src/shared/components/ui/Button.jsx +21 -0
- package/templates/css/component-styles/tailwind/feature-based/src/shared/components/ui/Button.tsx +26 -0
- package/templates/css/none/src/{index.css → main.css} +2 -0
- package/templates/css/none/src/themes.css +19 -0
- package/templates/css/tailwind/src/themes.css +9 -0
- package/templates/architectures/component-based/src/config/constants.js +0 -1
- package/templates/architectures/component-based/src/config/constants.ts +0 -1
- package/templates/architectures/component-based/src/config/routes.js +0 -7
- package/templates/architectures/component-based/src/config/routes.ts +0 -7
- package/templates/architectures/component-based/src/context/AppContext.jsx +0 -12
- package/templates/architectures/component-based/src/context/AppContext.tsx +0 -18
- package/templates/architectures/component-based/src/context/app-context.js +0 -5
- package/templates/architectures/component-based/src/hooks/index.js +0 -1
- package/templates/architectures/component-based/src/hooks/index.ts +0 -1
- package/templates/architectures/component-based/src/layouts/index.js +0 -1
- package/templates/architectures/component-based/src/layouts/index.ts +0 -1
- package/templates/architectures/component-based/src/styles/globals.css +0 -7
- package/templates/architectures/component-based/src/utils/index.js +0 -1
- package/templates/architectures/component-based/src/utils/index.ts +0 -1
- package/templates/architectures/feature-based/src/config/constants.js +0 -1
- package/templates/architectures/feature-based/src/config/constants.ts +0 -1
- package/templates/architectures/feature-based/src/hooks/index.js +0 -1
- package/templates/architectures/feature-based/src/hooks/index.ts +0 -1
- package/templates/architectures/feature-based/src/utils/index.js +0 -1
- package/templates/architectures/feature-based/src/utils/index.ts +0 -1
- package/templates/conditional/axios/component-based/src/services/axios.jsx +0 -19
- package/templates/conditional/axios/component-based/src/services/axios.ts +0 -19
- package/templates/conditional/axios/component-based/src/services/index.js +0 -1
- package/templates/conditional/axios/component-based/src/services/index.ts +0 -1
- package/templates/conditional/axios/feature-based/src/lib/axios.jsx +0 -19
- package/templates/conditional/axios/feature-based/src/lib/axios.ts +0 -19
- package/templates/conditional/axios/feature-based/src/lib/index.js +0 -1
- package/templates/conditional/axios/feature-based/src/lib/index.ts +0 -1
- package/templates/conditional/fetch/component-based/src/services/api.jsx +0 -27
- package/templates/conditional/fetch/component-based/src/services/api.ts +0 -27
- package/templates/conditional/fetch/component-based/src/services/index.js +0 -1
- package/templates/conditional/fetch/component-based/src/services/index.ts +0 -1
- package/templates/conditional/fetch/feature-based/src/lib/api.jsx +0 -27
- package/templates/conditional/fetch/feature-based/src/lib/api.ts +0 -27
- package/templates/conditional/fetch/feature-based/src/lib/index.js +0 -1
- package/templates/conditional/fetch/feature-based/src/lib/index.ts +0 -1
- package/templates/conditional/router/component-based/src/routes/index.jsx +0 -12
- package/templates/conditional/router/component-based/src/routes/index.tsx +0 -12
- package/templates/conditional/router/feature-based/src/app/router.jsx +0 -13
- package/templates/conditional/router/feature-based/src/app/router.tsx +0 -13
- package/templates/css/tailwind/src/index.css +0 -1
- /package/templates/architectures/component-based/src/{components/layout → config}/.gitkeep +0 -0
- /package/templates/architectures/{feature-based/src/features/home/interfaces → component-based/src/providers}/.gitkeep +0 -0
- /package/templates/architectures/{feature-based/src/lib → component-based/src/styles}/.gitkeep +0 -0
- /package/templates/architectures/feature-based/src/{stores → features/home/types}/.gitkeep +0 -0
- /package/templates/architectures/feature-based/src/{components → shared/components}/ui/index.js +0 -0
- /package/templates/architectures/feature-based/src/{components → shared/components}/ui/index.ts +0 -0
- /package/templates/architectures/feature-based/src/{hooks → shared/hooks}/useLocalStorage.jsx +0 -0
- /package/templates/architectures/feature-based/src/{hooks → shared/hooks}/useLocalStorage.ts +0 -0
- /package/templates/architectures/feature-based/src/{utils → shared/utils}/cn.jsx +0 -0
- /package/templates/architectures/feature-based/src/{utils → shared/utils}/cn.ts +0 -0
- /package/templates/conditional/state/redux/component-based/src/{context → providers}/StoreProvider.jsx +0 -0
- /package/templates/conditional/state/redux/component-based/src/{context → providers}/StoreProvider.tsx +0 -0
- /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/hooks.js +0 -0
- /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/hooks.ts +0 -0
- /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/index.js +0 -0
- /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/index.ts +0 -0
- /package/templates/css/bootstrap/src/{index.css → globals.css} +0 -0
- /package/templates/{architectures/feature-based/src/styles → css/tailwind/src}/globals.css +0 -0
package/README.md
CHANGED
|
@@ -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
|
-
│
|
|
95
|
-
|
|
96
|
-
│ └──
|
|
97
|
-
├──
|
|
98
|
-
│
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
│ ├──
|
|
105
|
+
│ ├── hooks
|
|
106
|
+
│ ├── index.ts # public feature barrel
|
|
103
107
|
│ ├── layouts
|
|
104
108
|
│ ├── pages
|
|
105
109
|
│ ├── services
|
|
106
|
-
│
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
├──
|
|
111
|
-
|
|
112
|
-
├──
|
|
113
|
-
├──
|
|
114
|
-
├──
|
|
115
|
-
|
|
116
|
-
├──
|
|
117
|
-
│ └──
|
|
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,31 @@ src/
|
|
|
126
130
|
├── App.tsx
|
|
127
131
|
├── components
|
|
128
132
|
│ ├── common
|
|
129
|
-
│
|
|
130
|
-
|
|
131
|
-
├── config
|
|
132
|
-
│ ├── constants.ts
|
|
133
|
-
│ └── routes.ts
|
|
134
|
-
├── context
|
|
135
|
-
├── hooks
|
|
136
|
-
├── index.css
|
|
133
|
+
│ └── form
|
|
134
|
+
├── config # API config (when an axios/fetch client is chosen)
|
|
137
135
|
├── layouts
|
|
138
136
|
├── main.tsx
|
|
139
137
|
├── pages
|
|
140
|
-
├──
|
|
138
|
+
├── providers # Provider components (createContext + Provider in separate files inside providers/)
|
|
139
|
+
│ ├── appcontext.ts # createContext + AppContextValue
|
|
140
|
+
│ └── AppProvider.tsx # Provider component
|
|
141
|
+
├── hooks
|
|
142
|
+
│ └── useApp.ts # Hook that reads AppContext
|
|
143
|
+
├── router # Centralized data router
|
|
144
|
+
│ ├── guards # AuthGuard, GuestGuard
|
|
145
|
+
│ └── index.tsx # Single source of truth for all routes
|
|
141
146
|
├── services
|
|
142
147
|
├── store
|
|
143
148
|
├── styles
|
|
149
|
+
│ ├── globals.css # Tailwind/Bootstrap directives (or main.css for vanilla)
|
|
150
|
+
│ └── themes.css # Theme tokens (Tailwind @theme / Bootstrap data-bs-theme / CSS vars)
|
|
144
151
|
├── test
|
|
145
152
|
└── utils
|
|
146
153
|
```
|
|
147
154
|
|
|
148
155
|
## Roadmap
|
|
149
156
|
|
|
150
|
-
|
|
157
|
+
Released versions live in [`docs/CHANGELOG.md`](./docs/CHANGELOG.md); planned work is tracked in [`docs/ROADMAP.md`](./docs/ROADMAP.md).
|
|
151
158
|
|
|
152
159
|
## Requirements
|
|
153
160
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-lumen",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Scaffold a React + Vite project with architecture choice: feature-based or component-based.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-lumen": "bin/cli.js"
|
|
8
8
|
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/LUMEN-SH/create-lumen"
|
|
12
|
+
},
|
|
9
13
|
"files": [
|
|
10
14
|
"bin/",
|
|
11
15
|
"register.js",
|
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) {
|
|
@@ -154,7 +154,7 @@ async function addPathAliasesToViteConfig(projectPath, ext) {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
async function configurePackageJson(projectPath) {
|
|
157
|
+
async function configurePackageJson(projectPath, language) {
|
|
158
158
|
const pkgPath = path.join(projectPath, "package.json");
|
|
159
159
|
try {
|
|
160
160
|
const content = await readFileContent(pkgPath);
|
|
@@ -166,6 +166,10 @@ async function configurePackageJson(projectPath) {
|
|
|
166
166
|
pkg.scripts.build = "vite build";
|
|
167
167
|
pkg.scripts.preview = "vite preview";
|
|
168
168
|
|
|
169
|
+
if (language === "ts") {
|
|
170
|
+
pkg.scripts.typecheck = "tsc -b";
|
|
171
|
+
}
|
|
172
|
+
|
|
169
173
|
await fsp.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
170
174
|
} catch {
|
|
171
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,23 +7,27 @@ 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
|
-
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
const
|
|
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");
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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");
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
if (cssFramework === "tailwind") {
|
|
@@ -36,14 +39,19 @@ export async function setupCssFramework({
|
|
|
36
39
|
);
|
|
37
40
|
await fsp.writeFile(viteConfigTarget, viteConfigContent, "utf8");
|
|
38
41
|
|
|
39
|
-
const
|
|
40
|
-
path.join(cssDir, "tailwind", "src", "
|
|
42
|
+
const globalsContent = await fsp.readFile(
|
|
43
|
+
path.join(cssDir, "tailwind", "src", "globals.css"),
|
|
44
|
+
"utf8"
|
|
45
|
+
);
|
|
46
|
+
const themesContent = await fsp.readFile(
|
|
47
|
+
path.join(cssDir, "tailwind", "src", "themes.css"),
|
|
41
48
|
"utf8"
|
|
42
49
|
);
|
|
43
|
-
await writeCss(
|
|
50
|
+
await writeCss(globalsContent, "globals.css");
|
|
51
|
+
await writeCss(themesContent, "themes.css");
|
|
44
52
|
} else if (cssFramework === "bootstrap") {
|
|
45
53
|
const mainFile = path.join(projectPath, "src", `main.${ext}`);
|
|
46
|
-
|
|
54
|
+
try {
|
|
47
55
|
let mainContent = await fsp.readFile(mainFile, "utf8");
|
|
48
56
|
if (
|
|
49
57
|
!mainContent.includes("bootstrap/dist/css/bootstrap.min.css")
|
|
@@ -52,20 +60,59 @@ export async function setupCssFramework({
|
|
|
52
60
|
"import 'bootstrap/dist/css/bootstrap.min.css';\n" + mainContent;
|
|
53
61
|
await fsp.writeFile(mainFile, mainContent, "utf8");
|
|
54
62
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
} catch {}
|
|
64
|
+
|
|
65
|
+
const globalsContent = await fsp.readFile(
|
|
66
|
+
path.join(cssDir, "bootstrap", "src", "globals.css"),
|
|
58
67
|
"utf8"
|
|
59
68
|
);
|
|
60
|
-
await
|
|
69
|
+
const themesContent = await fsp.readFile(
|
|
70
|
+
path.join(cssDir, "bootstrap", "src", "themes.css"),
|
|
71
|
+
"utf8"
|
|
72
|
+
);
|
|
73
|
+
await writeCss(globalsContent, "globals.css");
|
|
74
|
+
await writeCss(themesContent, "themes.css");
|
|
61
75
|
} else {
|
|
62
|
-
const
|
|
63
|
-
path.join(cssDir, "none", "src", "
|
|
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"),
|
|
64
82
|
"utf8"
|
|
65
83
|
);
|
|
66
|
-
await writeCss(
|
|
84
|
+
await writeCss(mainContent, "main.css");
|
|
85
|
+
await writeCss(themesContent, "themes.css");
|
|
67
86
|
}
|
|
68
87
|
|
|
69
|
-
//
|
|
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.
|
|
70
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 {}
|
|
71
118
|
}
|
package/src/dependencies.js
CHANGED
|
@@ -25,6 +25,20 @@ export async function installDeps(pkgManager, dev, packages, cwd) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export async function installAllDeps(responses, pkg, cwd) {
|
|
28
|
+
const { deps, devDeps } = computeDeps(responses);
|
|
29
|
+
|
|
30
|
+
if (deps.length > 0) {
|
|
31
|
+
await installDeps(pkg, false, deps, cwd);
|
|
32
|
+
}
|
|
33
|
+
if (devDeps.length > 0) {
|
|
34
|
+
await installDeps(pkg, true, devDeps, cwd);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Pure dependency computation — the package list for a given matrix cell,
|
|
39
|
+
// independent of any package manager or filesystem. Unit-tested directly so
|
|
40
|
+
// the conditional wiring stays verifiable without a network install.
|
|
41
|
+
export function computeDeps(responses) {
|
|
28
42
|
const deps = [];
|
|
29
43
|
const devDeps = [];
|
|
30
44
|
|
|
@@ -107,10 +121,5 @@ export async function installAllDeps(responses, pkg, cwd) {
|
|
|
107
121
|
// Always re-install react + react-dom for consistency
|
|
108
122
|
deps.push("react", "react-dom");
|
|
109
123
|
|
|
110
|
-
|
|
111
|
-
await installDeps(pkg, false, deps, cwd);
|
|
112
|
-
}
|
|
113
|
-
if (devDeps.length > 0) {
|
|
114
|
-
await installDeps(pkg, true, devDeps, cwd);
|
|
115
|
-
}
|
|
124
|
+
return { deps, devDeps };
|
|
116
125
|
}
|
package/src/injector.js
CHANGED
|
@@ -2,7 +2,25 @@ import { promises as fsp } from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { copyDirRecursive, writeFileRecursive } from "@/utils/fs.js";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// Narrow a template tree copy to the selected language: .tsx/.ts for ts,
|
|
6
|
+
// .jsx/.js for js (keeps the opposite language's files out of the project).
|
|
7
|
+
function langFileFilter(language) {
|
|
8
|
+
return (name) => {
|
|
9
|
+
if (language === "ts") {
|
|
10
|
+
if (name.endsWith(".jsx")) return false;
|
|
11
|
+
if (name.endsWith(".js")) return false;
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (language === "js") {
|
|
15
|
+
if (name.endsWith(".tsx")) return false;
|
|
16
|
+
if (name.endsWith(".ts")) return false;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function injectArchitecture(projectPath, templatesDir, architecture, language, cssFramework) {
|
|
6
24
|
const ext = language === "ts" ? "tsx" : "jsx";
|
|
7
25
|
const srcDir = path.join(templatesDir, "architectures", architecture, "src");
|
|
8
26
|
|
|
@@ -11,17 +29,13 @@ export async function injectArchitecture(projectPath, templatesDir, architecture
|
|
|
11
29
|
const defaultAppJsx = path.join(projectPath, "src", "App.jsx");
|
|
12
30
|
try { await fsp.rm(defaultAppTsx, { force: true }); } catch {}
|
|
13
31
|
try { await fsp.rm(defaultAppJsx, { force: true }); } catch {}
|
|
32
|
+
// Remove Vite's default index.css (framework CSS lives in src/styles/,
|
|
33
|
+
// copied below — never at the src/ root).
|
|
34
|
+
try { await fsp.rm(path.join(projectPath, "src", "index.css"), { force: true }); } catch {}
|
|
35
|
+
try { await fsp.rm(path.join(projectPath, "src", "App.css"), { force: true }); } catch {}
|
|
14
36
|
|
|
15
37
|
// Copy the architecture tree into the project's src/
|
|
16
|
-
await copyDirRecursive(srcDir, path.join(projectPath, "src"), (
|
|
17
|
-
// Skip files that don't match the language
|
|
18
|
-
if (language === "ts" && name.endsWith(".jsx")) return false;
|
|
19
|
-
if (language === "js" && name.endsWith(".tsx")) return false;
|
|
20
|
-
// Skip .ts files when JS, skip .js when TS (for non-component files)
|
|
21
|
-
if (language === "ts" && name.endsWith(".js") && !name.endsWith(".config.js")) return false;
|
|
22
|
-
if (language === "js" && name.endsWith(".ts") && !name.endsWith(".config.ts")) return false;
|
|
23
|
-
return true;
|
|
24
|
-
});
|
|
38
|
+
await copyDirRecursive(srcDir, path.join(projectPath, "src"), langFileFilter(language));
|
|
25
39
|
|
|
26
40
|
// Copy the architecture's main.tsx/main.jsx to src/main.{ext}
|
|
27
41
|
const mainSrc = path.join(
|
|
@@ -41,6 +55,31 @@ export async function injectArchitecture(projectPath, templatesDir, architecture
|
|
|
41
55
|
const oppositeExt = language === "ts" ? "jsx" : "tsx";
|
|
42
56
|
const oppositeMain = path.join(projectPath, "src", `main.${oppositeExt}`);
|
|
43
57
|
try { await fsp.rm(oppositeMain, { force: true }); } catch {}
|
|
58
|
+
|
|
59
|
+
// Apply the chosen CSS framework's component styling on top of the base
|
|
60
|
+
// (only where the base ships framework-agnostic inline markup). Runs here,
|
|
61
|
+
// before conditional overlays, so icons/router can still override the files
|
|
62
|
+
// they own.
|
|
63
|
+
if (cssFramework === "tailwind" || cssFramework === "bootstrap") {
|
|
64
|
+
const variantSrc = path.join(
|
|
65
|
+
templatesDir,
|
|
66
|
+
"css",
|
|
67
|
+
"component-styles",
|
|
68
|
+
cssFramework,
|
|
69
|
+
architecture,
|
|
70
|
+
"src"
|
|
71
|
+
);
|
|
72
|
+
try {
|
|
73
|
+
await fsp.access(variantSrc);
|
|
74
|
+
await copyDirRecursive(
|
|
75
|
+
variantSrc,
|
|
76
|
+
path.join(projectPath, "src"),
|
|
77
|
+
langFileFilter(language)
|
|
78
|
+
);
|
|
79
|
+
} catch {
|
|
80
|
+
// no component-styles for this arch/framework
|
|
81
|
+
}
|
|
82
|
+
}
|
|
44
83
|
}
|
|
45
84
|
|
|
46
85
|
export async function injectFormatter(projectPath, templatesDir, responses) {
|
|
@@ -153,20 +192,22 @@ export async function injectConditionals(projectPath, templatesDir, responses, a
|
|
|
153
192
|
|
|
154
193
|
// 2. Router (overwrites App.tsx with routed version)
|
|
155
194
|
if (responses.router) {
|
|
156
|
-
await
|
|
195
|
+
await injectOverlayVariant(
|
|
157
196
|
projectPath,
|
|
158
197
|
templatesDir,
|
|
159
|
-
`
|
|
198
|
+
`router/${architecture}`,
|
|
199
|
+
responses.cssFramework,
|
|
160
200
|
language
|
|
161
201
|
);
|
|
162
202
|
}
|
|
163
203
|
|
|
164
204
|
// 3. Icons (overwrites home page)
|
|
165
205
|
if (responses.iconLibrary && responses.iconLibrary !== "none") {
|
|
166
|
-
await
|
|
206
|
+
await injectOverlayVariant(
|
|
167
207
|
projectPath,
|
|
168
208
|
templatesDir,
|
|
169
|
-
`
|
|
209
|
+
`icons/${responses.iconLibrary}/${architecture}`,
|
|
210
|
+
responses.cssFramework,
|
|
170
211
|
language
|
|
171
212
|
);
|
|
172
213
|
}
|
|
@@ -206,19 +247,70 @@ export async function injectConditionals(projectPath, templatesDir, responses, a
|
|
|
206
247
|
if (architecture === "feature-based") {
|
|
207
248
|
await injectCreateFeatureScript(projectPath, templatesDir, language);
|
|
208
249
|
}
|
|
250
|
+
|
|
251
|
+
// A .gitkeep only keeps a folder alive when that folder holds nothing else;
|
|
252
|
+
// once an overlay writes real files into it the placeholder is redundant.
|
|
253
|
+
await pruneRedundantGitkeeps(projectPath);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Remove .gitkeep placeholders from src/ directories that now contain real
|
|
257
|
+
// files (e.g. component-based `services/.gitkeep` after the axios/fetch client
|
|
258
|
+
// overlay lands). A folder with nothing but its placeholder keeps it.
|
|
259
|
+
async function pruneRedundantGitkeeps(projectPath) {
|
|
260
|
+
const walk = async (dir) => {
|
|
261
|
+
let entries;
|
|
262
|
+
try {
|
|
263
|
+
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
264
|
+
} catch {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
for (const entry of entries) {
|
|
268
|
+
if (entry.isDirectory()) {
|
|
269
|
+
await walk(path.join(dir, entry.name));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (entries.some((e) => e.name === ".gitkeep")) {
|
|
273
|
+
const hasRealFiles = entries.some((e) => e.isFile() && e.name !== ".gitkeep");
|
|
274
|
+
if (hasRealFiles) {
|
|
275
|
+
await fsp.rm(path.join(dir, ".gitkeep"), { force: true });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
await walk(path.join(projectPath, "src"));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Overlays that ship presentational components (router, icons) carry optional
|
|
283
|
+
// tailwind/bootstrap subfolders. Copy the root version first — it holds the
|
|
284
|
+
// framework-agnostic skeleton (routed App, route tables) plus the inline
|
|
285
|
+
// markup defaults used for cssFramework "none" — then overlay the framework's
|
|
286
|
+
// subfolder so its markup-specific files (transitive layouts, home pages)
|
|
287
|
+
// win; `copyDirRecursive` overwrites on name collision.
|
|
288
|
+
async function injectOverlayVariant(projectPath, templatesDir, rel, cssFramework, language) {
|
|
289
|
+
const base = `conditional/${rel}`;
|
|
290
|
+
await injectOverlay(projectPath, templatesDir, base, language);
|
|
291
|
+
const variant =
|
|
292
|
+
cssFramework === "tailwind" || cssFramework === "bootstrap"
|
|
293
|
+
? cssFramework
|
|
294
|
+
: "";
|
|
295
|
+
if (variant) {
|
|
296
|
+
await injectOverlay(
|
|
297
|
+
projectPath,
|
|
298
|
+
templatesDir,
|
|
299
|
+
`${base}/${variant}`,
|
|
300
|
+
language
|
|
301
|
+
);
|
|
302
|
+
}
|
|
209
303
|
}
|
|
210
304
|
|
|
211
305
|
async function injectOverlay(projectPath, templatesDir, overlayPath, language) {
|
|
212
306
|
const srcDir = path.join(templatesDir, overlayPath, "src");
|
|
213
307
|
try {
|
|
214
308
|
await fsp.access(srcDir);
|
|
215
|
-
await copyDirRecursive(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return true;
|
|
221
|
-
});
|
|
309
|
+
await copyDirRecursive(
|
|
310
|
+
srcDir,
|
|
311
|
+
path.join(projectPath, "src"),
|
|
312
|
+
langFileFilter(language)
|
|
313
|
+
);
|
|
222
314
|
} catch {
|
|
223
315
|
// overlay src dir doesn't exist
|
|
224
316
|
}
|
|
@@ -332,11 +424,11 @@ async function injectCreateFeatureScript(projectPath, templatesDir, language) {
|
|
|
332
424
|
if (language === "js") {
|
|
333
425
|
// Replace .ts extensions with .js in the initialFiles
|
|
334
426
|
content = content
|
|
335
|
-
.replace(/interfaces\/index\.ts/g, "interfaces/index.js")
|
|
336
427
|
.replace(/services\/index\.ts/g, "services/index.js")
|
|
337
428
|
.replace(/store\/index\.ts/g, "store/index.js")
|
|
338
429
|
.replace(/hooks\/index\.ts/g, "hooks/index.js")
|
|
339
|
-
.replace(/pages\/index\.ts/g, "pages/index.js")
|
|
430
|
+
.replace(/pages\/index\.ts/g, "pages/index.js")
|
|
431
|
+
.replace(/types\/index\.ts/g, "types/index.js");
|
|
340
432
|
}
|
|
341
433
|
|
|
342
434
|
await writeFileRecursive(scriptDest, content);
|
|
@@ -373,7 +465,7 @@ async function updateMainWithProvider(projectPath, stateType, architecture, ext)
|
|
|
373
465
|
if (!content.includes("StoreProvider")) {
|
|
374
466
|
content = content.replace(
|
|
375
467
|
/import App from ['"]\.\/App['"]\n?/,
|
|
376
|
-
"import App from './App'\nimport { StoreProvider } from './
|
|
468
|
+
"import App from './App'\nimport { StoreProvider } from './providers/StoreProvider'\n"
|
|
377
469
|
);
|
|
378
470
|
content = content.replace(
|
|
379
471
|
/<App \/>/,
|
package/src/main.js
CHANGED
|
@@ -111,7 +111,8 @@ export async function main(options = {}) {
|
|
|
111
111
|
projectPath,
|
|
112
112
|
TEMPLATES_DIR,
|
|
113
113
|
responses.architecture,
|
|
114
|
-
responses.language
|
|
114
|
+
responses.language,
|
|
115
|
+
responses.cssFramework
|
|
115
116
|
);
|
|
116
117
|
archSpin.stop(chalk.green("Architecture scaffolding complete."));
|
|
117
118
|
} catch (err) {
|
|
@@ -175,6 +176,7 @@ export async function main(options = {}) {
|
|
|
175
176
|
templatesDir: TEMPLATES_DIR,
|
|
176
177
|
language: responses.language,
|
|
177
178
|
cssFramework: responses.cssFramework,
|
|
179
|
+
architecture: responses.architecture,
|
|
178
180
|
ext: responses.language === "ts" ? "tsx" : "jsx",
|
|
179
181
|
pkg,
|
|
180
182
|
});
|
package/src/readme.js
CHANGED
|
@@ -80,34 +80,76 @@ function buildScripts(responses) {
|
|
|
80
80
|
rows.push("| `npm run format:check` | Verify code is formatted |");
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
if (responses.language === "ts") {
|
|
84
|
+
rows.push("| `npm run typecheck` | Type-check the project (tsc -b) |");
|
|
85
|
+
}
|
|
86
|
+
|
|
83
87
|
return rows.join("\n");
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
function buildProjectStructure(
|
|
87
|
-
if (architecture === "feature-based") {
|
|
90
|
+
function buildProjectStructure(responses) {
|
|
91
|
+
if (responses.architecture === "feature-based") {
|
|
92
|
+
const shared = [];
|
|
93
|
+
if (responses.apiClient === "fetch") {
|
|
94
|
+
shared.push("api/ # HTTP client (fetch) — not an external dependency");
|
|
95
|
+
} else if (responses.apiClient === "axios") {
|
|
96
|
+
shared.push("lib/ # Third-party library init (axios client)");
|
|
97
|
+
}
|
|
98
|
+
shared.push(
|
|
99
|
+
"components/ # Shared UI components",
|
|
100
|
+
"hooks/ # Shared custom hooks",
|
|
101
|
+
"layouts/ # High-level layout wrappers",
|
|
102
|
+
"stores/ # Global state stores",
|
|
103
|
+
`styles/ # ${responses.cssFramework === "none" ? "main.css (reset) + themes.css (CSS variables)" : "globals.css (framework directives) + themes.css"}`,
|
|
104
|
+
"types/ # Global type definitions",
|
|
105
|
+
"utils/ # Pure utility functions"
|
|
106
|
+
);
|
|
107
|
+
const appChildren = [
|
|
108
|
+
"App.tsx",
|
|
109
|
+
"contexts/ # React context objects (createContext)",
|
|
110
|
+
"providers/ # Provider components (ThemeProvider, ...)",
|
|
111
|
+
"hooks/ # Hooks that read the contexts (useTheme, ...)"
|
|
112
|
+
];
|
|
88
113
|
return `src/
|
|
89
|
-
├── app/ # App shell and providers
|
|
90
|
-
|
|
91
|
-
├──
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
├── types/ # TypeScript type definitions
|
|
96
|
-
└── utils/ # Utility functions`;
|
|
114
|
+
├── app/ # App shell and global providers
|
|
115
|
+
${nestedTree(appChildren)}
|
|
116
|
+
├── features/ # Feature modules (pages, hooks, api, types)
|
|
117
|
+
│ └── home/ # Example feature (components, services, types, store)
|
|
118
|
+
└── shared/ # Reusable, business-agnostic resources
|
|
119
|
+
${nestedTree(shared)}`;
|
|
97
120
|
}
|
|
98
121
|
|
|
122
|
+
const rows = ["components/ # Reusable UI components (common, form)"];
|
|
123
|
+
if (responses.apiClient !== "none") {
|
|
124
|
+
rows.push("config/ # API configuration (axios/fetch)");
|
|
125
|
+
}
|
|
126
|
+
rows.push(
|
|
127
|
+
"hooks/ # Shared custom hooks",
|
|
128
|
+
"layouts/ # Page layout wrappers",
|
|
129
|
+
"pages/ # Page-level components",
|
|
130
|
+
"providers/ # Provider components (createContext in appcontext.{ts,js}, Provider in AppProvider.{tsx,jsx})"
|
|
131
|
+
);
|
|
132
|
+
if (responses.router) {
|
|
133
|
+
rows.push("router/ # Centralized data router (guards/, index)");
|
|
134
|
+
}
|
|
135
|
+
rows.push(
|
|
136
|
+
"services/ # API service layer",
|
|
137
|
+
"store/ # State store",
|
|
138
|
+
`styles/ # ${responses.cssFramework === "none" ? "main.css (reset) + themes.css (CSS variables)" : "globals.css (framework directives) + themes.css"}`,
|
|
139
|
+
"types/ # TypeScript type definitions",
|
|
140
|
+
"utils/ # Utility functions"
|
|
141
|
+
);
|
|
99
142
|
return `src/
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
└── utils/ # Utility functions`;
|
|
143
|
+
${nestedTree(rows, "")}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function nestedTree(rows, indent = " ") {
|
|
147
|
+
return rows
|
|
148
|
+
.map((label, i) => {
|
|
149
|
+
const isLast = i === rows.length - 1;
|
|
150
|
+
return `${indent}${isLast ? "└── " : "├── "}${label}`;
|
|
151
|
+
})
|
|
152
|
+
.join("\n");
|
|
111
153
|
}
|
|
112
154
|
|
|
113
155
|
function buildLicense() {
|
|
@@ -153,7 +195,7 @@ function buildDescription(projectName, responses) {
|
|
|
153
195
|
function buildReadme(projectName, responses) {
|
|
154
196
|
const builtWith = buildBuiltWith(responses);
|
|
155
197
|
const scripts = buildScripts(responses);
|
|
156
|
-
const structure = buildProjectStructure(responses
|
|
198
|
+
const structure = buildProjectStructure(responses);
|
|
157
199
|
|
|
158
200
|
return `${buildDescription(projectName, responses)}
|
|
159
201
|
|