@codefast/cli 0.3.1-canary.5 → 0.3.1-canary.6
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/CHANGELOG.md +12 -0
- package/dist/index.cjs +216 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +215 -154
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @codefast/cli
|
|
2
2
|
|
|
3
|
+
## 0.3.1-canary.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`ed2ba2c`](https://github.com/codefastlabs/codefast/commit/ed2ba2cd81cfbf5764fe4631b9de9a5dcaa6ddfa) Thanks [@thevuong](https://github.com/thevuong)! - feat(cli): add cleanup step to remove unnecessary packages
|
|
8
|
+
|
|
9
|
+
- [`ee7c42f`](https://github.com/codefastlabs/codefast/commit/ee7c42f2ad157288c11e2cfbc2d2dbb52be8a6b5) Thanks [@thevuong](https://github.com/thevuong)! - feat(cli): update layout.tsx with fontVariables support
|
|
10
|
+
|
|
11
|
+
- [`53b416f`](https://github.com/codefastlabs/codefast/commit/53b416f7cb45c7d6d5834aa853c59c38ca1fbba8) Thanks [@thevuong](https://github.com/thevuong)! - feat(cli): modularize project creation functionalities
|
|
12
|
+
|
|
13
|
+
- [`24a767b`](https://github.com/codefastlabs/codefast/commit/24a767b8be3bb0cbe63a3ab3b13ab64130341218) Thanks [@thevuong](https://github.com/thevuong)! - refactor(cli): improve config file handling in project setup
|
|
14
|
+
|
|
3
15
|
## 0.3.1-canary.5
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -26,55 +26,32 @@ var __webpack_require__ = {};
|
|
|
26
26
|
})();
|
|
27
27
|
var __webpack_exports__ = {};
|
|
28
28
|
const external_commander_namespaceObject = require("commander");
|
|
29
|
-
const external_node_child_process_namespaceObject = require("node:child_process");
|
|
30
29
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
31
30
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
32
31
|
const external_node_path_namespaceObject = require("node:path");
|
|
33
32
|
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
33
|
+
const external_node_child_process_namespaceObject = require("node:child_process");
|
|
34
34
|
const external_node_readline_namespaceObject = require("node:readline");
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"@codefast/hooks"
|
|
38
|
-
];
|
|
39
|
-
const DEV_DEPENDENCIES = {
|
|
40
|
-
commitLint: [
|
|
41
|
-
"@commitlint/cli",
|
|
42
|
-
"@commitlint/config-conventional",
|
|
43
|
-
"@commitlint/types"
|
|
44
|
-
],
|
|
45
|
-
gitTools: [
|
|
46
|
-
"simple-git-hooks"
|
|
47
|
-
],
|
|
48
|
-
formatting: [
|
|
49
|
-
"prettier",
|
|
50
|
-
"prettier-plugin-packagejson",
|
|
51
|
-
"prettier-plugin-tailwindcss",
|
|
52
|
-
"lint-staged"
|
|
53
|
-
],
|
|
54
|
-
linting: [
|
|
55
|
-
"@codefast/eslint-config"
|
|
56
|
-
]
|
|
57
|
-
};
|
|
58
|
-
const rl = external_node_readline_namespaceObject.createInterface({
|
|
35
|
+
var external_node_readline_default = /*#__PURE__*/ __webpack_require__.n(external_node_readline_namespaceObject);
|
|
36
|
+
const rl = external_node_readline_default().createInterface({
|
|
59
37
|
input: process.stdin,
|
|
60
38
|
output: process.stdout
|
|
61
39
|
});
|
|
62
|
-
function
|
|
40
|
+
function utils_prompt(question) {
|
|
63
41
|
return new Promise((resolve)=>{
|
|
64
42
|
rl.question(question, (answer)=>{
|
|
65
43
|
resolve(answer.trim());
|
|
66
44
|
});
|
|
67
45
|
});
|
|
68
46
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
47
|
+
function runCommand(command) {
|
|
48
|
+
(0, external_node_child_process_namespaceObject.execSync)(command, {
|
|
49
|
+
stdio: "inherit"
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function writeConfigFile(filePath, content) {
|
|
53
|
+
external_node_fs_default().writeFileSync(filePath, content);
|
|
54
|
+
console.log(`📝 Created ${filePath}`);
|
|
78
55
|
}
|
|
79
56
|
function validateProjectName(name) {
|
|
80
57
|
if (!name || /^\s*$/.test(name)) return {
|
|
@@ -99,13 +76,13 @@ function validateProjectName(name) {
|
|
|
99
76
|
valid: false,
|
|
100
77
|
error: `Project name "${name}" is a reserved system name.`
|
|
101
78
|
};
|
|
102
|
-
const fullPath =
|
|
103
|
-
if (
|
|
79
|
+
const fullPath = external_node_path_default().resolve(process.cwd(), name);
|
|
80
|
+
if (external_node_fs_default().existsSync(fullPath)) return {
|
|
104
81
|
valid: false,
|
|
105
82
|
error: `A directory named "${name}" already exists.`
|
|
106
83
|
};
|
|
107
84
|
try {
|
|
108
|
-
|
|
85
|
+
external_node_fs_default().accessSync(process.cwd(), external_node_fs_default().constants.W_OK);
|
|
109
86
|
} catch {
|
|
110
87
|
return {
|
|
111
88
|
valid: false,
|
|
@@ -117,36 +94,67 @@ function validateProjectName(name) {
|
|
|
117
94
|
};
|
|
118
95
|
}
|
|
119
96
|
async function getValidProjectName(initialName, attempts = 0, maxAttempts = 3) {
|
|
120
|
-
const projectName = initialName ?? await
|
|
97
|
+
const projectName = initialName ?? await utils_prompt("Enter project name: ");
|
|
121
98
|
const validation = validateProjectName(projectName);
|
|
122
99
|
if (validation.valid) return projectName;
|
|
123
|
-
if (attempts >= maxAttempts - 1) throw new Error(
|
|
100
|
+
if (attempts >= maxAttempts - 1) throw new Error(`❌ Exceeded maximum attempts to enter a valid project name.`);
|
|
124
101
|
console.error(`❌ ${validation.error} (${maxAttempts - attempts - 1} attempts remaining)`);
|
|
125
102
|
return getValidProjectName(void 0, attempts + 1, maxAttempts);
|
|
126
103
|
}
|
|
127
|
-
function
|
|
128
|
-
(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
content = content.replace("const config = {", `${typeComment}const config = {`);
|
|
144
|
-
external_node_fs_namespaceObject.writeFileSync(postcssConfigPath, content);
|
|
145
|
-
console.log("📝 Updated postcss.config.mjs with type comment.");
|
|
104
|
+
async function checkExistingProject(projectNameArg) {
|
|
105
|
+
const packageJsonPath = external_node_path_default().join(process.cwd(), "package.json");
|
|
106
|
+
const packageJsonExists = external_node_fs_default().existsSync(packageJsonPath);
|
|
107
|
+
if (packageJsonExists) {
|
|
108
|
+
console.log(`⚠️ A package.json file has been detected in the current directory.`);
|
|
109
|
+
const confirm = await utils_prompt("Do you want to continue configuring this existing project? [Y/n]: ");
|
|
110
|
+
if ("" === confirm || "y" === confirm.toLowerCase()) {
|
|
111
|
+
const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, "utf8"));
|
|
112
|
+
const projectName = packageJson.name ?? await getValidProjectName(projectNameArg);
|
|
113
|
+
return {
|
|
114
|
+
projectName,
|
|
115
|
+
packageJsonExists
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
console.log("Aborting...");
|
|
119
|
+
throw new Error("User aborted the operation.");
|
|
146
120
|
}
|
|
121
|
+
const projectName = await getValidProjectName(projectNameArg);
|
|
122
|
+
return {
|
|
123
|
+
projectName,
|
|
124
|
+
packageJsonExists
|
|
125
|
+
};
|
|
147
126
|
}
|
|
148
|
-
const
|
|
149
|
-
"
|
|
127
|
+
const MAIN_DEPENDENCIES = [
|
|
128
|
+
"@codefast/ui",
|
|
129
|
+
"@codefast/hooks"
|
|
130
|
+
];
|
|
131
|
+
const DEV_DEPENDENCIES = {
|
|
132
|
+
commitLint: [
|
|
133
|
+
"@commitlint/cli",
|
|
134
|
+
"@commitlint/config-conventional",
|
|
135
|
+
"@commitlint/types"
|
|
136
|
+
],
|
|
137
|
+
gitTools: [
|
|
138
|
+
"simple-git-hooks"
|
|
139
|
+
],
|
|
140
|
+
formatting: [
|
|
141
|
+
"prettier",
|
|
142
|
+
"prettier-plugin-packagejson",
|
|
143
|
+
"prettier-plugin-tailwindcss",
|
|
144
|
+
"lint-staged"
|
|
145
|
+
],
|
|
146
|
+
linting: [
|
|
147
|
+
"@codefast/eslint-config"
|
|
148
|
+
]
|
|
149
|
+
};
|
|
150
|
+
const PACKAGES_TO_REMOVE = [
|
|
151
|
+
"@eslint/eslintrc"
|
|
152
|
+
];
|
|
153
|
+
const configGroups = {
|
|
154
|
+
linting: [
|
|
155
|
+
{
|
|
156
|
+
path: "commitlint.config.mjs",
|
|
157
|
+
content: `/**
|
|
150
158
|
* @see https://commitlint.js.org/reference/configuration.html
|
|
151
159
|
* @type {import('@commitlint/types').UserConfig}
|
|
152
160
|
*/
|
|
@@ -156,24 +164,25 @@ const config = {
|
|
|
156
164
|
"body-max-line-length": [2, "always", 350],
|
|
157
165
|
},
|
|
158
166
|
};
|
|
159
|
-
|
|
160
167
|
export default config;
|
|
161
168
|
`,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
169
|
+
description: "Commitlint configuration"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
path: "eslint.config.mjs",
|
|
173
|
+
content: `import { config } from "@codefast/eslint-config/next";
|
|
174
|
+
/**
|
|
175
|
+
* @see https://eslint.org/docs/latest/use/configure/configuration-files
|
|
176
|
+
* @type {import('eslint').Linter.Config[]}
|
|
165
177
|
*/
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
printWidth: 100,
|
|
169
|
-
tailwindAttributes: ["classNames"],
|
|
170
|
-
tailwindFunctions: ["tv"],
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
export default config;
|
|
178
|
+
const eslintConfig = [...config];
|
|
179
|
+
export default eslintConfig;
|
|
174
180
|
`,
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
description: "ESLint configuration for the project"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
path: "lint-staged.config.mjs",
|
|
185
|
+
content: `import { relative } from "node:path";
|
|
177
186
|
/**
|
|
178
187
|
* Builds an ESLint command with the given filenames.
|
|
179
188
|
*
|
|
@@ -185,7 +194,6 @@ function buildEslintCommand(filenames) {
|
|
|
185
194
|
return \`next lint --fix --max-warnings 0 --file \${filenames.map((file) => relative(import.meta.dirname, file)).
|
|
186
195
|
join(" --file ")}\`;
|
|
187
196
|
}
|
|
188
|
-
|
|
189
197
|
/**
|
|
190
198
|
* @see https://www.npmjs.com/package/lint-staged
|
|
191
199
|
* @type {import('lint-staged').Configuration}
|
|
@@ -194,138 +202,117 @@ const config = {
|
|
|
194
202
|
"*.{js,mjs,jsx,ts,tsx}": [buildEslintCommand, "prettier --list-different --write"],
|
|
195
203
|
"*.{json,css,md,mdx}": ["prettier --list-different --write"],
|
|
196
204
|
};
|
|
197
|
-
|
|
198
205
|
export default config;
|
|
199
206
|
`,
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
207
|
+
description: "Configure lint-staged for pre-commit checks"
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
formatting: [
|
|
211
|
+
{
|
|
212
|
+
path: "prettier.config.mjs",
|
|
213
|
+
content: `/**
|
|
214
|
+
* @see https://prettier.io/docs/en/configuration.html
|
|
215
|
+
* @type {import('prettier').Config}
|
|
204
216
|
*/
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
217
|
+
const config = {
|
|
218
|
+
plugins: ["prettier-plugin-packagejson", "prettier-plugin-tailwindcss"],
|
|
219
|
+
printWidth: 100,
|
|
220
|
+
tailwindAttributes: ["classNames"],
|
|
221
|
+
tailwindFunctions: ["tv"],
|
|
222
|
+
};
|
|
223
|
+
export default config;
|
|
208
224
|
`,
|
|
209
|
-
|
|
225
|
+
description: "Prettier configuration for source code formatting"
|
|
226
|
+
}
|
|
227
|
+
],
|
|
228
|
+
styles: [
|
|
229
|
+
{
|
|
230
|
+
path: "src/lib/fonts.ts",
|
|
231
|
+
content: `import { cn } from "@codefast/ui";
|
|
210
232
|
import { Geist, Geist_Mono as GeistMono } from "next/font/google";
|
|
211
|
-
|
|
212
233
|
const fontGeistSans = Geist({
|
|
213
234
|
subsets: ["latin"],
|
|
214
235
|
variable: "--font-geist-sans",
|
|
215
236
|
});
|
|
216
|
-
|
|
217
237
|
const fontGeistMono = GeistMono({
|
|
218
238
|
subsets: ["latin"],
|
|
219
239
|
variable: "--font-geist-mono",
|
|
220
240
|
});
|
|
221
|
-
|
|
222
241
|
export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
|
|
223
242
|
`,
|
|
224
|
-
|
|
225
|
-
|
|
243
|
+
description: "Font configuration for the application"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
path: "src/app/globals.css",
|
|
247
|
+
content: `@import "tailwindcss";
|
|
226
248
|
@import "@codefast/ui/styles.css";
|
|
227
|
-
|
|
228
249
|
@source '../../node_modules/@codefast/ui';
|
|
229
|
-
|
|
230
250
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
231
|
-
|
|
232
|
-
@theme inline {
|
|
233
|
-
--font-sans: var(--font-geist-sans);
|
|
234
|
-
--font-mono: var(--font-geist-mono);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
251
|
@layer base {
|
|
238
252
|
:root {
|
|
253
|
+
--font-sans: var(--font-geist-sans);
|
|
254
|
+
--font-mono: var(--font-geist-mono);
|
|
239
255
|
--input: var(--color-neutral-200);
|
|
240
256
|
--border: var(--color-neutral-200);
|
|
241
|
-
|
|
242
257
|
--ring: var(--color-neutral-400);
|
|
243
|
-
|
|
244
258
|
--background: var(--color-white);
|
|
245
259
|
--foreground: var(--color-neutral-950);
|
|
246
|
-
|
|
247
260
|
--primary: var(--color-sky-500);
|
|
248
261
|
--primary-foreground: var(--color-neutral-50);
|
|
249
|
-
|
|
250
262
|
--secondary: var(--color-neutral-100);
|
|
251
263
|
--secondary-foreground: var(--color-neutral-900);
|
|
252
|
-
|
|
253
264
|
--destructive: var(--color-red-600);
|
|
254
|
-
|
|
255
265
|
--accent: var(--color-neutral-100);
|
|
256
266
|
--accent-foreground: var(--color-neutral-900);
|
|
257
|
-
|
|
258
267
|
--muted: var(--color-neutral-100);
|
|
259
268
|
--muted-foreground: var(--color-neutral-500);
|
|
260
|
-
|
|
261
269
|
--popover: var(--color-white);
|
|
262
270
|
--popover-foreground: var(--color-neutral-950);
|
|
263
271
|
--popover-overlay: --alpha(var(--color-neutral-900) / 20%);
|
|
264
|
-
|
|
265
272
|
--card: var(--color-white);
|
|
266
273
|
--card-foreground: var(--color-neutral-950);
|
|
267
|
-
|
|
268
274
|
--sidebar: var(--color-neutral-50);
|
|
269
275
|
--sidebar-foreground: var(--color-neutral-950);
|
|
270
|
-
|
|
271
276
|
--sidebar-primary: var(--color-sky-500);
|
|
272
277
|
--sidebar-primary-foreground: var(--color-neutral-50);
|
|
273
|
-
|
|
274
278
|
--sidebar-accent: var(--color-neutral-100);
|
|
275
279
|
--sidebar-accent-foreground: var(--color-neutral-900);
|
|
276
|
-
|
|
277
280
|
--sidebar-border: var(--color-neutral-200);
|
|
278
281
|
--sidebar-ring: var(--color-neutral-400);
|
|
279
|
-
|
|
280
282
|
--chart-1: var(--color-orange-600);
|
|
281
283
|
--chart-2: var(--color-teal-600);
|
|
282
284
|
--chart-3: var(--color-cyan-600);
|
|
283
285
|
--chart-4: var(--color-amber-600);
|
|
284
286
|
--chart-5: var(--color-amber-500);
|
|
285
287
|
}
|
|
286
|
-
|
|
287
288
|
@variant dark {
|
|
288
289
|
--input: var(--color-neutral-700);
|
|
289
290
|
--border: --alpha(var(--color-neutral-700) / 50%);
|
|
290
|
-
|
|
291
291
|
--ring: var(--color-neutral-500);
|
|
292
|
-
|
|
293
292
|
--background: var(--color-neutral-950);
|
|
294
293
|
--foreground: var(--color-neutral-50);
|
|
295
|
-
|
|
296
294
|
--primary: var(--color-sky-700);
|
|
297
295
|
--primary-foreground: var(--color-neutral-50);
|
|
298
|
-
|
|
299
296
|
--secondary: var(--color-neutral-800);
|
|
300
297
|
--secondary-foreground: var(--color-neutral-50);
|
|
301
|
-
|
|
302
298
|
--destructive: var(--color-red-400);
|
|
303
|
-
|
|
304
299
|
--accent: var(--color-neutral-700);
|
|
305
300
|
--accent-foreground: var(--color-neutral-50);
|
|
306
|
-
|
|
307
301
|
--muted: var(--color-neutral-800);
|
|
308
302
|
--muted-foreground: var(--color-neutral-400);
|
|
309
|
-
|
|
310
303
|
--popover: var(--color-neutral-800);
|
|
311
304
|
--popover-foreground: var(--color-neutral-50);
|
|
312
305
|
--popover-overlay: --alpha(var(--color-neutral-900) / 80%);
|
|
313
|
-
|
|
314
306
|
--card: var(--color-neutral-900);
|
|
315
307
|
--card-foreground: var(--color-neutral-50);
|
|
316
|
-
|
|
317
308
|
--sidebar: var(--color-neutral-900);
|
|
318
309
|
--sidebar-foreground: var(--color-neutral-50);
|
|
319
|
-
|
|
320
310
|
--sidebar-primary: var(--color-sky-700);
|
|
321
311
|
--sidebar-primary-foreground: var(--color-neutral-50);
|
|
322
|
-
|
|
323
312
|
--sidebar-accent: var(--color-neutral-800);
|
|
324
313
|
--sidebar-accent-foreground: var(--color-neutral-50);
|
|
325
|
-
|
|
326
314
|
--sidebar-border: var(--color-neutral-800);
|
|
327
315
|
--sidebar-ring: var(--color-neutral-600);
|
|
328
|
-
|
|
329
316
|
--chart-1: var(--color-blue-700);
|
|
330
317
|
--chart-2: var(--color-emerald-500);
|
|
331
318
|
--chart-3: var(--color-amber-500);
|
|
@@ -333,11 +320,54 @@ export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
|
|
|
333
320
|
--chart-5: var(--color-rose-500);
|
|
334
321
|
}
|
|
335
322
|
}
|
|
336
|
-
|
|
323
|
+
`,
|
|
324
|
+
description: "Global CSS variables for the application"
|
|
325
|
+
}
|
|
326
|
+
]
|
|
337
327
|
};
|
|
328
|
+
function updatePostcssConfig(projectDir) {
|
|
329
|
+
const postcssConfigPath = external_node_path_default().join(projectDir, "postcss.config.mjs");
|
|
330
|
+
if (!external_node_fs_default().existsSync(postcssConfigPath)) return void console.warn(`⚠️ postcss.config.mjs not found, skipping update.`);
|
|
331
|
+
let content = external_node_fs_default().readFileSync(postcssConfigPath, "utf8");
|
|
332
|
+
const typeComment = `/** @type {import('postcss-load-config').Config} */\n`;
|
|
333
|
+
if (content.includes(typeComment)) console.log(`📝 postcss.config.mjs already contains type comment, no changes made.`);
|
|
334
|
+
else {
|
|
335
|
+
content = content.replace("const config = {", `${typeComment}const config = {`);
|
|
336
|
+
external_node_fs_default().writeFileSync(postcssConfigPath, content);
|
|
337
|
+
console.log(`📝 Updated postcss.config.mjs with type comment.`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function updateLayoutFile(projectDir) {
|
|
341
|
+
const layoutPath = external_node_path_default().join(projectDir, "src/app/layout.tsx");
|
|
342
|
+
if (!external_node_fs_default().existsSync(layoutPath)) return void console.warn(`⚠️ src/app/layout.tsx not found, skipping update.`);
|
|
343
|
+
let content = external_node_fs_default().readFileSync(layoutPath, "utf8");
|
|
344
|
+
if (content.includes('<html className={cn(fontVariables, "antialiased")} lang="en">')) return void console.log(`📝 src/app/layout.tsx already uses fontVariables in html tag, no changes made.`);
|
|
345
|
+
const newImports = `import type { Metadata } from "next";
|
|
346
|
+
|
|
347
|
+
import { cn } from "@codefast/ui";
|
|
348
|
+
|
|
349
|
+
import { fontVariables } from "@/lib/fonts";
|
|
350
|
+
import "@/app/globals.css";`;
|
|
351
|
+
content = content.replaceAll(/import\s+{[^}]+}\s+from\s+["']next\/font\/google["'];\s*/g, "");
|
|
352
|
+
content = content.replace(/const\s+geistSans\s*=[^;]+;\s*const\s+geistMono\s*=[^;]+;\s*/, "");
|
|
353
|
+
content = content.replace(/import\s+type\s+{[^}]+}\s+from\s+["']next["'];\s*import\s+["']\.\/globals\.css["'];\s*/, newImports);
|
|
354
|
+
const htmlRegex = /<html\s+lang="en"\s*>/;
|
|
355
|
+
const newHtml = '<html className={cn(fontVariables, "antialiased")} lang="en">';
|
|
356
|
+
content = content.replace(htmlRegex, newHtml);
|
|
357
|
+
const bodyRegex = /<body\s+className={`[^`]*`}\s*>/;
|
|
358
|
+
const newBody = "<body>";
|
|
359
|
+
content = content.replace(bodyRegex, newBody);
|
|
360
|
+
try {
|
|
361
|
+
external_node_fs_default().writeFileSync(layoutPath, content);
|
|
362
|
+
console.log(`📝 Updated src/app/layout.tsx to use fontVariables in html tag and removed className from body`);
|
|
363
|
+
} catch (error) {
|
|
364
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
365
|
+
console.warn(`⚠️ Failed to update src/app/layout.tsx: ${errorMessage}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
338
368
|
function updatePackageJson(projectDir) {
|
|
339
|
-
const packageJsonPath =
|
|
340
|
-
const packageJson = JSON.parse(
|
|
369
|
+
const packageJsonPath = external_node_path_default().join(projectDir, "package.json");
|
|
370
|
+
const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, "utf8"));
|
|
341
371
|
packageJson.scripts = {
|
|
342
372
|
...packageJson.scripts,
|
|
343
373
|
format: 'prettier --write "**/*.{js,mjs,jsx,ts,tsx,json,css,md,mdx}"',
|
|
@@ -348,67 +378,99 @@ function updatePackageJson(projectDir) {
|
|
|
348
378
|
"pre-commit": "pnpm lint-staged",
|
|
349
379
|
"commit-msg": "pnpm commitlint --edit"
|
|
350
380
|
};
|
|
351
|
-
|
|
352
|
-
console.log(
|
|
381
|
+
external_node_fs_default().writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
382
|
+
console.log(`📝 Updated package.json`);
|
|
353
383
|
}
|
|
354
|
-
function
|
|
355
|
-
console.log(
|
|
356
|
-
const
|
|
357
|
-
|
|
384
|
+
function createConfigFiles(projectDir) {
|
|
385
|
+
console.log(`\n📝 Creating configuration files...`);
|
|
386
|
+
for (const [category, configs] of Object.entries(configGroups)){
|
|
387
|
+
console.log(`\n📂 Setting up ${category} configurations:`);
|
|
388
|
+
for (const { path: filePath, content, description } of configs){
|
|
389
|
+
const fullPath = external_node_path_default().join(projectDir, filePath);
|
|
390
|
+
const dir = external_node_path_default().dirname(fullPath);
|
|
391
|
+
if (!external_node_fs_default().existsSync(dir)) external_node_fs_default().mkdirSync(dir, {
|
|
392
|
+
recursive: true
|
|
393
|
+
});
|
|
394
|
+
writeConfigFile(fullPath, content);
|
|
395
|
+
if (description) console.log(` ℹ️ ${filePath}: ${description}`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
358
398
|
}
|
|
359
399
|
function installDependencies() {
|
|
360
|
-
console.log(
|
|
400
|
+
console.log(`\n📚 Installing dependencies...`);
|
|
361
401
|
if (MAIN_DEPENDENCIES.length > 0) runCommand(`pnpm add ${MAIN_DEPENDENCIES.join(" ")}`);
|
|
362
402
|
const allDevDependencies = Object.values(DEV_DEPENDENCIES).flat().join(" ");
|
|
363
403
|
if (allDevDependencies) runCommand(`pnpm add -D ${allDevDependencies}`);
|
|
364
404
|
}
|
|
365
|
-
function
|
|
366
|
-
console.log(`\n
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
405
|
+
function cleanupPackages() {
|
|
406
|
+
console.log(`\n🧹 Cleaning up unnecessary packages...`);
|
|
407
|
+
const packageJsonPath = external_node_path_namespaceObject.join(process.cwd(), "package.json");
|
|
408
|
+
if (!external_node_fs_namespaceObject.existsSync(packageJsonPath)) return void console.warn(`⚠️ package.json not found, skipping cleanup.`);
|
|
409
|
+
let packageJson;
|
|
410
|
+
try {
|
|
411
|
+
packageJson = JSON.parse(external_node_fs_namespaceObject.readFileSync(packageJsonPath, "utf8"));
|
|
412
|
+
} catch (error) {
|
|
413
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
414
|
+
console.warn(`⚠️ Error reading package.json: ${errorMessage}, skipping cleanup.`);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const dependencies = packageJson.dependencies ?? {};
|
|
418
|
+
const devDependencies = packageJson.devDependencies ?? {};
|
|
419
|
+
const packagesToRemove = PACKAGES_TO_REMOVE.filter((pkg)=>pkg in dependencies || pkg in devDependencies);
|
|
420
|
+
if (packagesToRemove.length > 0) runCommand(`pnpm remove ${packagesToRemove.join(" ")}`);
|
|
421
|
+
else console.log(`ℹ️ No unnecessary packages found in package.json to remove.`);
|
|
422
|
+
}
|
|
423
|
+
function checkEnvironment() {
|
|
424
|
+
try {
|
|
425
|
+
(0, external_node_child_process_namespaceObject.execSync)("pnpm --version", {
|
|
426
|
+
stdio: "ignore"
|
|
372
427
|
});
|
|
373
|
-
|
|
428
|
+
} catch {
|
|
429
|
+
console.error(`❌ PNPM chưa được cài đặt. Vui lòng cài đặt PNPM trước.`);
|
|
430
|
+
process.exit(1);
|
|
374
431
|
}
|
|
375
432
|
}
|
|
433
|
+
function createNextProject(projectName) {
|
|
434
|
+
console.log(`📦 Creating Next.js project...`);
|
|
435
|
+
const flags = '--ts --tailwind --eslint --app --turbo --use-pnpm --src-dir --turbopack --import-alias "@/*"';
|
|
436
|
+
runCommand(`npx create-next-app@latest ${projectName} ${flags}`);
|
|
437
|
+
}
|
|
376
438
|
function createProjectCommand(program) {
|
|
377
439
|
program.command("create-project [name]").description("Create a new Next.js project with recommended setup").action(async (projectNameArg)=>{
|
|
378
440
|
try {
|
|
379
441
|
checkEnvironment();
|
|
380
|
-
const projectName = await
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (packageJsonExists) console.log(`📦 A package.json file has been detected. Skipping the Next.js project creation step.`);
|
|
384
|
-
else {
|
|
442
|
+
const { projectName, packageJsonExists } = await checkExistingProject(projectNameArg);
|
|
443
|
+
if (!packageJsonExists) {
|
|
444
|
+
console.log(`\n🚀 Starting project creation for ${projectName}...\n`);
|
|
385
445
|
createNextProject(projectName);
|
|
386
446
|
process.chdir(projectName);
|
|
387
447
|
console.log(`📂 Moved to ${projectName}`);
|
|
388
448
|
}
|
|
449
|
+
updateLayoutFile(process.cwd());
|
|
389
450
|
updatePostcssConfig(process.cwd());
|
|
390
451
|
installDependencies();
|
|
452
|
+
cleanupPackages();
|
|
391
453
|
createConfigFiles(process.cwd());
|
|
392
454
|
updatePackageJson(process.cwd());
|
|
393
455
|
console.log(`\n🔄 Activating git hooks...`);
|
|
394
456
|
runCommand("pnpm simple-git-hooks");
|
|
395
457
|
console.log(`\n📝 Formatting files with Prettier...`);
|
|
396
458
|
runCommand("pnpm format");
|
|
397
|
-
console.log(`\n✅ Project created successfully!`);
|
|
459
|
+
console.log(`\n✅ Project ${packageJsonExists ? "configured" : "created"} successfully!`);
|
|
398
460
|
console.log(`- Project: ${projectName}`);
|
|
399
461
|
console.log("- Next.js with TypeScript");
|
|
400
462
|
console.log("- TailwindCSS and @codefast/ui");
|
|
401
463
|
console.log("- ESLint, Prettier, Commitlint, and Git Hooks");
|
|
402
464
|
console.log("- Lint-staged for pre-commit checks");
|
|
403
|
-
console.log(`\n📁 Project directory: ${
|
|
465
|
+
console.log(`\n📁 Project directory: ${process.cwd()}`);
|
|
404
466
|
console.log(`\n🚀 To start development:`);
|
|
405
467
|
console.log(`cd ${projectName} && pnpm dev`);
|
|
406
|
-
rl.close();
|
|
407
468
|
} catch (error) {
|
|
408
469
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
409
470
|
console.error(`\n❌ An error occurred: ${errorMessage}`);
|
|
410
|
-
rl.close();
|
|
411
471
|
process.exit(1);
|
|
472
|
+
} finally{
|
|
473
|
+
rl.close();
|
|
412
474
|
}
|
|
413
475
|
});
|
|
414
476
|
}
|