initkit 1.1.0 → 1.2.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.
- package/README.md +109 -117
- package/package.json +2 -5
- package/src/cli.js +77 -34
- package/src/commands/create.js +173 -84
- package/src/prompts/questions.js +95 -39
- package/src/utils/addonInstaller.js +402 -0
- package/src/utils/cliRunner.js +146 -0
- package/src/utils/frameworkBootstrap.js +304 -0
- package/src/utils/templateGenerator.js +191 -171
- package/src/templates/express.js +0 -915
- package/src/templates/fullstack.js +0 -1236
- package/src/templates/nextjs.js +0 -620
- package/src/templates/react.js +0 -586
- package/src/templates/vue.js +0 -545
|
@@ -1,246 +1,266 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import
|
|
4
|
-
import { generateReactTemplate } from '../templates/react.js';
|
|
5
|
-
import { generateVueTemplate } from '../templates/vue.js';
|
|
6
|
-
import { generateExpressTemplate } from '../templates/express.js';
|
|
7
|
-
import { generateFullStackTemplate } from '../templates/fullstack.js';
|
|
3
|
+
import chalk from 'chalk';
|
|
8
4
|
|
|
9
5
|
/**
|
|
10
6
|
* Generate project files from templates based on user configuration
|
|
7
|
+
*
|
|
8
|
+
* NOTE: With the new CLI-first approach, this function now focuses on
|
|
9
|
+
* ENHANCING the project created by official CLIs rather than creating
|
|
10
|
+
* everything from scratch. It adds custom folder structures on top of
|
|
11
|
+
* the base project.
|
|
12
|
+
*
|
|
11
13
|
* @param {string} projectPath - Absolute path to the project directory
|
|
12
14
|
* @param {Object} config - User's project configuration object
|
|
13
|
-
* @param {string} config.projectType - Type of project ('frontend'|'backend'|'
|
|
15
|
+
* @param {string} config.projectType - Type of project ('frontend'|'backend'|'library')
|
|
14
16
|
* @param {string} [config.frontend] - Frontend framework choice
|
|
15
17
|
* @param {string} [config.backend] - Backend framework choice
|
|
18
|
+
* @param {string} [config.folderStructure] - Folder structure preference
|
|
16
19
|
* @param {Array<string>} [config.features] - Additional features to enable
|
|
17
20
|
* @returns {Promise<void>}
|
|
18
21
|
* @throws {Error} If template generation fails
|
|
19
22
|
*/
|
|
20
23
|
async function generateTemplate(projectPath, config) {
|
|
21
|
-
|
|
22
|
-
await generateGitignore(projectPath, config);
|
|
24
|
+
console.log(chalk.dim('\n Adding custom folder structure...\n'));
|
|
23
25
|
|
|
24
|
-
//
|
|
26
|
+
// Add custom folder structure based on project type
|
|
25
27
|
switch (config.projectType) {
|
|
26
28
|
case 'frontend':
|
|
27
|
-
await
|
|
29
|
+
await enhanceFrontendStructure(projectPath, config);
|
|
28
30
|
break;
|
|
29
31
|
case 'backend':
|
|
30
|
-
await
|
|
31
|
-
break;
|
|
32
|
-
case 'fullstack':
|
|
33
|
-
await generateFullStackFiles(projectPath, config);
|
|
32
|
+
await enhanceBackendStructure(projectPath, config);
|
|
34
33
|
break;
|
|
35
34
|
case 'library':
|
|
36
|
-
await
|
|
35
|
+
await enhanceLibraryStructure(projectPath, config);
|
|
37
36
|
break;
|
|
37
|
+
default:
|
|
38
|
+
console.log(chalk.gray(' ✓ Using default project structure'));
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
// Add additional features (Docker, GitHub Actions, etc.)
|
|
41
42
|
if (config.features) {
|
|
42
43
|
await addFeatures(projectPath, config);
|
|
43
44
|
}
|
|
45
|
+
|
|
46
|
+
// Generate .env example files if needed
|
|
47
|
+
if (config.features && config.features.includes('dotenv')) {
|
|
48
|
+
await generateEnvFiles(projectPath, config);
|
|
49
|
+
}
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* @param {Object} config - User's project configuration
|
|
50
|
-
* @param {string} config.frontend - Frontend framework ('react'|'vue'|'nextjs'|'angular'|'svelte'|'nuxt')
|
|
51
|
-
* @param {string} config.language - Language choice ('typescript'|'javascript')
|
|
52
|
-
* @param {string} config.folderStructure - Folder structure preference
|
|
53
|
-
* @returns {Promise<void>}
|
|
54
|
-
* @throws {Error} If framework template is not found or generation fails
|
|
53
|
+
* Enhance frontend project with custom folder structure
|
|
54
|
+
* Adds folders on top of CLI-generated project
|
|
55
55
|
*/
|
|
56
|
-
async function
|
|
57
|
-
const
|
|
56
|
+
async function enhanceFrontendStructure(projectPath, config) {
|
|
57
|
+
const { folderStructure = 'feature-based' } = config;
|
|
58
|
+
const srcPath = path.join(projectPath, 'src');
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
// Ensure src directory exists (should already exist from CLI)
|
|
61
|
+
await fs.ensureDir(srcPath);
|
|
62
|
+
|
|
63
|
+
switch (folderStructure) {
|
|
64
|
+
case 'feature-based':
|
|
65
|
+
await createFeatureBasedStructure(srcPath, config);
|
|
62
66
|
break;
|
|
63
|
-
case '
|
|
64
|
-
await
|
|
67
|
+
case 'component-based':
|
|
68
|
+
await createComponentBasedStructure(srcPath, config);
|
|
65
69
|
break;
|
|
66
|
-
case '
|
|
67
|
-
await
|
|
70
|
+
case 'atomic':
|
|
71
|
+
await createAtomicStructure(srcPath, config);
|
|
68
72
|
break;
|
|
69
73
|
default:
|
|
70
|
-
|
|
71
|
-
`Frontend framework "${framework}" is not yet implemented. Available: react, nextjs, vue`
|
|
72
|
-
);
|
|
74
|
+
await createFeatureBasedStructure(srcPath, config);
|
|
73
75
|
}
|
|
76
|
+
|
|
77
|
+
console.log(chalk.gray(` ✓ Added ${folderStructure} folder structure`));
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
/**
|
|
77
|
-
*
|
|
78
|
-
* @param {string} projectPath - Absolute path to the project directory
|
|
79
|
-
* @param {Object} config - User's project configuration
|
|
80
|
-
* @param {string} config.backend - Backend framework ('express'|'fastify'|'nestjs'|'koa'|'hapi')
|
|
81
|
-
* @param {string} [config.database] - Database choice ('mongodb'|'postgresql'|'mysql'|'sqlite')
|
|
82
|
-
* @param {string} config.language - Language choice ('typescript'|'javascript')
|
|
83
|
-
* @param {string} config.projectName - Name of the project
|
|
84
|
-
* @param {string} config.packageManager - Package manager to use
|
|
85
|
-
* @returns {Promise<void>}
|
|
86
|
-
* @throws {Error} If backend template generation fails
|
|
81
|
+
* Create feature-based folder structure
|
|
87
82
|
*/
|
|
88
|
-
async function
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
83
|
+
async function createFeatureBasedStructure(srcPath, config) {
|
|
84
|
+
const features = ['auth', 'dashboard', 'users'];
|
|
85
|
+
|
|
86
|
+
for (const feature of features) {
|
|
87
|
+
await fs.ensureDir(path.join(srcPath, 'features', feature, 'components'));
|
|
88
|
+
await fs.ensureDir(path.join(srcPath, 'features', feature, 'hooks'));
|
|
89
|
+
await fs.ensureDir(path.join(srcPath, 'features', feature, 'services'));
|
|
90
|
+
await fs.ensureDir(path.join(srcPath, 'features', feature, 'types'));
|
|
91
|
+
|
|
92
|
+
// Add barrel export
|
|
93
|
+
const ext = config.language === 'typescript' ? 'ts' : 'js';
|
|
94
|
+
await fs.writeFile(
|
|
95
|
+
path.join(srcPath, 'features', feature, `index.${ext}`),
|
|
96
|
+
`// ${feature} feature exports\n// TODO: Export your components and hooks here\n`
|
|
97
|
+
);
|
|
97
98
|
}
|
|
99
|
+
|
|
100
|
+
// Add shared folder
|
|
101
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'components', 'ui'));
|
|
102
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'components', 'layout'));
|
|
103
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'hooks'));
|
|
104
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'utils'));
|
|
105
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'types'));
|
|
106
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'constants'));
|
|
98
107
|
}
|
|
99
108
|
|
|
100
109
|
/**
|
|
101
|
-
*
|
|
102
|
-
* @param {string} projectPath - Absolute path to the project directory
|
|
103
|
-
* @param {Object} config - User's project configuration
|
|
104
|
-
* @param {string} [config.fullstackType] - Project structure type ('monorepo'|'traditional')
|
|
105
|
-
* @param {string} [config.stack] - Technology stack ('MERN'|'PERN'|'T3'|etc)
|
|
106
|
-
* @param {string} [config.frontend] - Frontend framework
|
|
107
|
-
* @param {string} [config.backend] - Backend framework
|
|
108
|
-
* @returns {Promise<void>}
|
|
109
|
-
* @throws {Error} If full-stack template generation fails
|
|
110
|
+
* Create component-based folder structure
|
|
110
111
|
*/
|
|
111
|
-
async function
|
|
112
|
-
|
|
113
|
-
await
|
|
112
|
+
async function createComponentBasedStructure(srcPath, config) {
|
|
113
|
+
await fs.ensureDir(path.join(srcPath, 'components', 'ui'));
|
|
114
|
+
await fs.ensureDir(path.join(srcPath, 'components', 'layout'));
|
|
115
|
+
await fs.ensureDir(path.join(srcPath, 'components', 'forms'));
|
|
116
|
+
await fs.ensureDir(path.join(srcPath, 'pages'));
|
|
117
|
+
await fs.ensureDir(path.join(srcPath, 'hooks'));
|
|
118
|
+
await fs.ensureDir(path.join(srcPath, 'services'));
|
|
119
|
+
await fs.ensureDir(path.join(srcPath, 'utils'));
|
|
120
|
+
await fs.ensureDir(path.join(srcPath, 'types'));
|
|
121
|
+
await fs.ensureDir(path.join(srcPath, 'constants'));
|
|
114
122
|
}
|
|
115
123
|
|
|
116
124
|
/**
|
|
117
|
-
*
|
|
118
|
-
* @param {string} projectPath - Absolute path to the project directory
|
|
119
|
-
* @param {Object} config - User's project configuration
|
|
120
|
-
* @param {string} config.projectName - Name of the library
|
|
121
|
-
* @param {string} config.language - Language choice ('typescript'|'javascript')
|
|
122
|
-
* @param {string} config.packageManager - Package manager to use
|
|
123
|
-
* @returns {Promise<void>}
|
|
124
|
-
* @throws {Error} If library template generation fails
|
|
125
|
-
*/
|
|
126
|
-
async function generateLibraryFiles(projectPath, config) {
|
|
127
|
-
const srcPath = path.join(projectPath, 'src');
|
|
128
|
-
await fs.ensureDir(srcPath);
|
|
129
|
-
|
|
130
|
-
const ext = config.language === 'typescript' ? 'ts' : 'js';
|
|
131
|
-
|
|
132
|
-
const indexContent = `/**
|
|
133
|
-
* Main entry point for ${config.projectName}
|
|
125
|
+
* Create atomic design folder structure
|
|
134
126
|
*/
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
127
|
+
async function createAtomicStructure(srcPath, config) {
|
|
128
|
+
await fs.ensureDir(path.join(srcPath, 'components', 'atoms'));
|
|
129
|
+
await fs.ensureDir(path.join(srcPath, 'components', 'molecules'));
|
|
130
|
+
await fs.ensureDir(path.join(srcPath, 'components', 'organisms'));
|
|
131
|
+
await fs.ensureDir(path.join(srcPath, 'components', 'templates'));
|
|
132
|
+
await fs.ensureDir(path.join(srcPath, 'pages'));
|
|
133
|
+
await fs.ensureDir(path.join(srcPath, 'hooks'));
|
|
134
|
+
await fs.ensureDir(path.join(srcPath, 'services'));
|
|
135
|
+
await fs.ensureDir(path.join(srcPath, 'utils'));
|
|
136
|
+
await fs.ensureDir(path.join(srcPath, 'types'));
|
|
138
137
|
}
|
|
139
|
-
`;
|
|
140
|
-
|
|
141
|
-
await fs.writeFile(path.join(srcPath, `index.${ext}`), indexContent);
|
|
142
|
-
|
|
143
|
-
// Package.json for library
|
|
144
|
-
const packageJson = {
|
|
145
|
-
name: config.projectName,
|
|
146
|
-
version: '1.0.0',
|
|
147
|
-
description: 'A reusable library',
|
|
148
|
-
main: `dist/index.js`,
|
|
149
|
-
types: config.language === 'typescript' ? 'dist/index.d.ts' : undefined,
|
|
150
|
-
files: ['dist'],
|
|
151
|
-
scripts: {
|
|
152
|
-
build: 'echo "Configure build script"',
|
|
153
|
-
test: 'echo "Configure test script"',
|
|
154
|
-
},
|
|
155
|
-
keywords: [],
|
|
156
|
-
author: '',
|
|
157
|
-
license: 'MIT',
|
|
158
|
-
};
|
|
159
138
|
|
|
160
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Enhance backend project with custom folder structure
|
|
141
|
+
*/
|
|
142
|
+
async function enhanceBackendStructure(projectPath, config) {
|
|
143
|
+
const { folderStructure = 'mvc' } = config;
|
|
144
|
+
const srcPath = path.join(projectPath, 'src');
|
|
161
145
|
|
|
162
|
-
|
|
146
|
+
await fs.ensureDir(srcPath);
|
|
163
147
|
|
|
164
|
-
|
|
148
|
+
switch (folderStructure) {
|
|
149
|
+
case 'mvc':
|
|
150
|
+
await createMVCStructure(srcPath, config);
|
|
151
|
+
break;
|
|
152
|
+
case 'clean-architecture':
|
|
153
|
+
await createCleanArchitectureStructure(srcPath, config);
|
|
154
|
+
break;
|
|
155
|
+
case 'feature-based':
|
|
156
|
+
await createBackendFeatureBasedStructure(srcPath, config);
|
|
157
|
+
break;
|
|
158
|
+
case 'layered':
|
|
159
|
+
await createLayeredStructure(srcPath, config);
|
|
160
|
+
break;
|
|
161
|
+
default:
|
|
162
|
+
await createMVCStructure(srcPath, config);
|
|
163
|
+
}
|
|
165
164
|
|
|
166
|
-
|
|
165
|
+
console.log(chalk.gray(` ✓ Added ${folderStructure} folder structure`));
|
|
166
|
+
}
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Create MVC folder structure for backend
|
|
170
|
+
*/
|
|
171
|
+
async function createMVCStructure(srcPath, config) {
|
|
172
|
+
await fs.ensureDir(path.join(srcPath, 'models'));
|
|
173
|
+
await fs.ensureDir(path.join(srcPath, 'controllers'));
|
|
174
|
+
await fs.ensureDir(path.join(srcPath, 'routes'));
|
|
175
|
+
await fs.ensureDir(path.join(srcPath, 'middlewares'));
|
|
176
|
+
await fs.ensureDir(path.join(srcPath, 'services'));
|
|
177
|
+
await fs.ensureDir(path.join(srcPath, 'utils'));
|
|
178
|
+
await fs.ensureDir(path.join(srcPath, 'config'));
|
|
179
|
+
await fs.ensureDir(path.join(srcPath, 'types'));
|
|
180
|
+
}
|
|
171
181
|
|
|
172
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Create clean architecture structure
|
|
184
|
+
*/
|
|
185
|
+
async function createCleanArchitectureStructure(srcPath, config) {
|
|
186
|
+
await fs.ensureDir(path.join(srcPath, 'domain', 'entities'));
|
|
187
|
+
await fs.ensureDir(path.join(srcPath, 'domain', 'repositories'));
|
|
188
|
+
await fs.ensureDir(path.join(srcPath, 'domain', 'use-cases'));
|
|
189
|
+
await fs.ensureDir(path.join(srcPath, 'application', 'services'));
|
|
190
|
+
await fs.ensureDir(path.join(srcPath, 'infrastructure', 'database'));
|
|
191
|
+
await fs.ensureDir(path.join(srcPath, 'infrastructure', 'repositories'));
|
|
192
|
+
await fs.ensureDir(path.join(srcPath, 'presentation', 'controllers'));
|
|
193
|
+
await fs.ensureDir(path.join(srcPath, 'presentation', 'middlewares'));
|
|
194
|
+
await fs.ensureDir(path.join(srcPath, 'presentation', 'routes'));
|
|
195
|
+
}
|
|
173
196
|
|
|
174
|
-
|
|
175
|
-
|
|
197
|
+
/**
|
|
198
|
+
* Create feature-based structure for backend
|
|
199
|
+
*/
|
|
200
|
+
async function createBackendFeatureBasedStructure(srcPath, config) {
|
|
201
|
+
const features = ['auth', 'users', 'posts'];
|
|
202
|
+
|
|
203
|
+
for (const feature of features) {
|
|
204
|
+
await fs.ensureDir(path.join(srcPath, 'features', feature, 'controllers'));
|
|
205
|
+
await fs.ensureDir(path.join(srcPath, 'features', feature, 'services'));
|
|
206
|
+
await fs.ensureDir(path.join(srcPath, 'features', feature, 'models'));
|
|
207
|
+
await fs.ensureDir(path.join(srcPath, 'features', feature, 'routes'));
|
|
208
|
+
}
|
|
176
209
|
|
|
177
|
-
|
|
178
|
-
|
|
210
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'middlewares'));
|
|
211
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'utils'));
|
|
212
|
+
await fs.ensureDir(path.join(srcPath, 'shared', 'config'));
|
|
213
|
+
}
|
|
179
214
|
|
|
180
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Create layered structure
|
|
217
|
+
*/
|
|
218
|
+
async function createLayeredStructure(srcPath, config) {
|
|
219
|
+
await fs.ensureDir(path.join(srcPath, 'controllers'));
|
|
220
|
+
await fs.ensureDir(path.join(srcPath, 'services'));
|
|
221
|
+
await fs.ensureDir(path.join(srcPath, 'repositories'));
|
|
222
|
+
await fs.ensureDir(path.join(srcPath, 'models'));
|
|
223
|
+
await fs.ensureDir(path.join(srcPath, 'routes'));
|
|
224
|
+
await fs.ensureDir(path.join(srcPath, 'middlewares'));
|
|
225
|
+
await fs.ensureDir(path.join(srcPath, 'utils'));
|
|
226
|
+
await fs.ensureDir(path.join(srcPath, 'config'));
|
|
227
|
+
}
|
|
181
228
|
|
|
182
|
-
|
|
183
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Enhance library structure
|
|
231
|
+
*/
|
|
232
|
+
async function enhanceLibraryStructure(projectPath, config) {
|
|
233
|
+
const srcPath = path.join(projectPath, 'src');
|
|
234
|
+
await fs.ensureDir(srcPath);
|
|
235
|
+
await fs.ensureDir(path.join(srcPath, 'core'));
|
|
236
|
+
await fs.ensureDir(path.join(srcPath, 'utils'));
|
|
237
|
+
await fs.ensureDir(path.join(srcPath, 'types'));
|
|
238
|
+
await fs.ensureDir(path.join(projectPath, 'tests'));
|
|
239
|
+
await fs.ensureDir(path.join(projectPath, 'docs'));
|
|
184
240
|
|
|
185
|
-
|
|
241
|
+
console.log(chalk.gray(' ✓ Added library folder structure'));
|
|
186
242
|
}
|
|
187
243
|
|
|
188
244
|
/**
|
|
189
|
-
* Generate
|
|
190
|
-
* @param {string} projectPath - Absolute path to the project directory
|
|
191
|
-
* @param {Object} config - User's project configuration
|
|
192
|
-
* @param {string} config.projectType - Type of project ('frontend'|'backend'|'fullstack'|'library')
|
|
193
|
-
* @param {string} [config.frontend] - Frontend framework name
|
|
194
|
-
* @param {string} [config.backend] - Backend framework name
|
|
195
|
-
* @param {boolean} [config.monorepo] - Whether project uses monorepo structure
|
|
196
|
-
* @returns {Promise<void>}
|
|
197
|
-
* @throws {Error} If file creation fails
|
|
245
|
+
* Generate environment files
|
|
198
246
|
*/
|
|
199
|
-
async function
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
.pnp
|
|
203
|
-
.pnp.js
|
|
204
|
-
|
|
205
|
-
# Testing
|
|
206
|
-
coverage/
|
|
207
|
-
|
|
208
|
-
# Production
|
|
209
|
-
build/
|
|
210
|
-
dist/
|
|
211
|
-
.next/
|
|
212
|
-
out/
|
|
213
|
-
|
|
214
|
-
# Misc
|
|
215
|
-
.DS_Store
|
|
216
|
-
*.pem
|
|
217
|
-
|
|
218
|
-
# Debug
|
|
219
|
-
npm-debug.log*
|
|
220
|
-
yarn-debug.log*
|
|
221
|
-
yarn-error.log*
|
|
222
|
-
.pnpm-debug.log*
|
|
223
|
-
|
|
224
|
-
# Local env files
|
|
225
|
-
.env
|
|
226
|
-
.env*.local
|
|
247
|
+
async function generateEnvFiles(projectPath, config) {
|
|
248
|
+
const envExample = `# Environment Variables
|
|
249
|
+
# Copy this file to .env and fill in your values
|
|
227
250
|
|
|
228
|
-
#
|
|
229
|
-
|
|
251
|
+
# Application
|
|
252
|
+
NODE_ENV=development
|
|
253
|
+
PORT=3000
|
|
230
254
|
|
|
231
|
-
#
|
|
232
|
-
|
|
233
|
-
next-env.d.ts
|
|
255
|
+
# Database
|
|
256
|
+
DATABASE_URL=
|
|
234
257
|
|
|
235
|
-
#
|
|
236
|
-
|
|
237
|
-
.idea/
|
|
238
|
-
*.swp
|
|
239
|
-
*.swo
|
|
240
|
-
*~
|
|
258
|
+
# API Keys
|
|
259
|
+
API_KEY=
|
|
241
260
|
`;
|
|
242
261
|
|
|
243
|
-
await fs.writeFile(path.join(projectPath, '.
|
|
262
|
+
await fs.writeFile(path.join(projectPath, '.env.example'), envExample);
|
|
263
|
+
console.log(chalk.gray(' ✓ Added .env.example'));
|
|
244
264
|
}
|
|
245
265
|
|
|
246
266
|
/**
|