initkit 1.1.0 → 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.
@@ -1,246 +1,266 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
- import { generateNextjsTemplate } from '../templates/nextjs.js';
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'|'fullstack'|'library')
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
- // Generate .gitignore
22
- await generateGitignore(projectPath, config);
24
+ console.log(chalk.dim('\n Adding custom folder structure...\n'));
23
25
 
24
- // Generate project-specific files based on type
26
+ // Add custom folder structure based on project type
25
27
  switch (config.projectType) {
26
28
  case 'frontend':
27
- await generateFrontendFiles(projectPath, config);
29
+ await enhanceFrontendStructure(projectPath, config);
28
30
  break;
29
31
  case 'backend':
30
- await generateBackendFiles(projectPath, config);
31
- break;
32
- case 'fullstack':
33
- await generateFullStackFiles(projectPath, config);
32
+ await enhanceBackendStructure(projectPath, config);
34
33
  break;
35
34
  case 'library':
36
- await generateLibraryFiles(projectPath, config);
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
- * Generate frontend project files based on selected framework
48
- * @param {string} projectPath - Absolute path to the project directory
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 generateFrontendFiles(projectPath, config) {
57
- const framework = config.frontend;
56
+ async function enhanceFrontendStructure(projectPath, config) {
57
+ const { folderStructure = 'feature-based' } = config;
58
+ const srcPath = path.join(projectPath, 'src');
58
59
 
59
- switch (framework) {
60
- case 'nextjs':
61
- await generateNextjsTemplate(projectPath, config);
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 'react':
64
- await generateReactTemplate(projectPath, config);
67
+ case 'component-based':
68
+ await createComponentBasedStructure(srcPath, config);
65
69
  break;
66
- case 'vue':
67
- await generateVueTemplate(projectPath, config);
70
+ case 'atomic':
71
+ await createAtomicStructure(srcPath, config);
68
72
  break;
69
73
  default:
70
- throw new Error(
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
- * Generate backend project files based on selected framework
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 generateBackendFiles(projectPath, config) {
89
- const backend = config.backend;
90
-
91
- switch (backend) {
92
- case 'express':
93
- await generateExpressTemplate(projectPath, config);
94
- break;
95
- default:
96
- throw new Error(`Backend framework "${backend}" is not yet implemented. Available: express`);
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
- * Generate full-stack project with both frontend and backend
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 generateFullStackFiles(projectPath, config) {
112
- // Use the dedicated full-stack template generator
113
- await generateFullStackTemplate(projectPath, config);
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
- * Generate Node.js library/package structure
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
- export function hello() {
137
- return 'Hello from ${config.projectName}!';
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
- await fs.writeJSON(path.join(projectPath, 'package.json'), packageJson, { spaces: 2 });
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
- const readme = `# ${config.projectName}
146
+ await fs.ensureDir(srcPath);
163
147
 
164
- Library created with InitKit CLI
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
- ## Installation
165
+ console.log(chalk.gray(` ✓ Added ${folderStructure} folder structure`));
166
+ }
167
167
 
168
- \`\`\`bash
169
- npm install ${config.projectName}
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
- ## Usage
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
- \`\`\`javascript
175
- import { hello } from '${config.projectName}';
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
- console.log(hello());
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
- Built with InitKit
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
- await fs.writeFile(path.join(projectPath, 'README.md'), readme);
241
+ console.log(chalk.gray(' ✓ Added library folder structure'));
186
242
  }
187
243
 
188
244
  /**
189
- * Generate .gitignore file with framework-specific patterns
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 generateGitignore(projectPath, _config) {
200
- const gitignore = `# Dependencies
201
- node_modules/
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
- # Vercel
229
- .vercel
251
+ # Application
252
+ NODE_ENV=development
253
+ PORT=3000
230
254
 
231
- # TypeScript
232
- *.tsbuildinfo
233
- next-env.d.ts
255
+ # Database
256
+ DATABASE_URL=
234
257
 
235
- # IDE
236
- .vscode/
237
- .idea/
238
- *.swp
239
- *.swo
240
- *~
258
+ # API Keys
259
+ API_KEY=
241
260
  `;
242
261
 
243
- await fs.writeFile(path.join(projectPath, '.gitignore'), gitignore);
262
+ await fs.writeFile(path.join(projectPath, '.env.example'), envExample);
263
+ console.log(chalk.gray(' ✓ Added .env.example'));
244
264
  }
245
265
 
246
266
  /**