@codefast/cli 0.3.1-canary.5 → 0.3.1-canary.8
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 +24 -0
- package/dist/index.cjs +327 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +326 -146
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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,49 +94,139 @@ 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
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
+
]
|
|
158
149
|
};
|
|
159
|
-
|
|
160
|
-
|
|
150
|
+
const PACKAGES_TO_REMOVE = [
|
|
151
|
+
"@eslint/eslintrc"
|
|
152
|
+
];
|
|
153
|
+
const configGroups = {
|
|
154
|
+
deployment: [
|
|
155
|
+
{
|
|
156
|
+
path: ".vercelignore",
|
|
157
|
+
content: `#-------------------------------------------------------------------------------
|
|
158
|
+
# Dependencies and package managers
|
|
159
|
+
#-------------------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
# Node dependencies
|
|
162
|
+
node_modules
|
|
163
|
+
.pnpm-store
|
|
164
|
+
.yarn
|
|
165
|
+
|
|
166
|
+
#-------------------------------------------------------------------------------
|
|
167
|
+
# Development and environment
|
|
168
|
+
#-------------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
# Environment variables (except examples)
|
|
171
|
+
.env*
|
|
172
|
+
!.env.example
|
|
173
|
+
|
|
174
|
+
# Build artifacts
|
|
175
|
+
.next
|
|
176
|
+
build
|
|
177
|
+
dist
|
|
178
|
+
.git
|
|
179
|
+
.github
|
|
180
|
+
.turbo
|
|
181
|
+
.changeset
|
|
182
|
+
.eslintcache
|
|
183
|
+
|
|
184
|
+
# Debug logs
|
|
185
|
+
npm-debug.log*
|
|
186
|
+
yarn-debug.log*
|
|
187
|
+
|
|
188
|
+
#-------------------------------------------------------------------------------
|
|
189
|
+
# Testing
|
|
190
|
+
#-------------------------------------------------------------------------------
|
|
191
|
+
|
|
192
|
+
# Test coverage reports and config snapshots
|
|
193
|
+
coverage
|
|
194
|
+
*.test.*
|
|
195
|
+
*.e2e.*
|
|
196
|
+
|
|
197
|
+
#-------------------------------------------------------------------------------
|
|
198
|
+
# Editor and IDE configuration
|
|
199
|
+
#-------------------------------------------------------------------------------
|
|
200
|
+
|
|
201
|
+
# IDE project files
|
|
202
|
+
.idea
|
|
203
|
+
*.suo
|
|
204
|
+
*.ntvs*
|
|
205
|
+
*.njsproj
|
|
206
|
+
*.sln
|
|
207
|
+
|
|
208
|
+
#-------------------------------------------------------------------------------
|
|
209
|
+
# Operating system files
|
|
210
|
+
#-------------------------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
# System metadata files
|
|
213
|
+
.DS_Store
|
|
214
|
+
Thumbs.db
|
|
215
|
+
|
|
216
|
+
#-------------------------------------------------------------------------------
|
|
217
|
+
# Deployment
|
|
218
|
+
#-------------------------------------------------------------------------------
|
|
219
|
+
|
|
220
|
+
# Vercel deployment configuration
|
|
221
|
+
.vercel
|
|
161
222
|
`,
|
|
162
|
-
|
|
223
|
+
description: "Ignore files that should not be deployed to Vercel"
|
|
224
|
+
}
|
|
225
|
+
],
|
|
226
|
+
formatting: [
|
|
227
|
+
{
|
|
228
|
+
path: "prettier.config.mjs",
|
|
229
|
+
content: `/**
|
|
163
230
|
* @see https://prettier.io/docs/en/configuration.html
|
|
164
231
|
* @type {import('prettier').Config}
|
|
165
232
|
*/
|
|
@@ -172,8 +239,71 @@ const config = {
|
|
|
172
239
|
|
|
173
240
|
export default config;
|
|
174
241
|
`,
|
|
175
|
-
|
|
242
|
+
description: "Prettier configuration for source code formatting"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
path: ".editorconfig",
|
|
246
|
+
content: `# https://editorconfig.org
|
|
247
|
+
root = true
|
|
248
|
+
|
|
249
|
+
[*]
|
|
250
|
+
charset = utf-8
|
|
251
|
+
insert_final_newline = true
|
|
252
|
+
|
|
253
|
+
end_of_line = lf
|
|
254
|
+
indent_style = space
|
|
255
|
+
indent_size = 2
|
|
256
|
+
max_line_length = 120
|
|
257
|
+
|
|
258
|
+
trim_trailing_whitespace = true
|
|
259
|
+
|
|
260
|
+
[Makefile]
|
|
261
|
+
indent_style = tab
|
|
262
|
+
|
|
263
|
+
[{go.mod,go.sum,*.go}]
|
|
264
|
+
indent_style = tab
|
|
176
265
|
|
|
266
|
+
[*.rs]
|
|
267
|
+
# Keep in sync with rustfmt
|
|
268
|
+
indent_size = 4
|
|
269
|
+
`,
|
|
270
|
+
description: "Editor configuration for source code formatting"
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
linting: [
|
|
274
|
+
{
|
|
275
|
+
path: "commitlint.config.mjs",
|
|
276
|
+
content: `/**
|
|
277
|
+
* @see https://commitlint.js.org/reference/configuration.html
|
|
278
|
+
* @type {import('@commitlint/types').UserConfig}
|
|
279
|
+
*/
|
|
280
|
+
const config = {
|
|
281
|
+
extends: ["@commitlint/config-conventional"],
|
|
282
|
+
rules: {
|
|
283
|
+
"body-max-line-length": [2, "always", 350],
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
export default config;
|
|
288
|
+
`,
|
|
289
|
+
description: "Commitlint configuration"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
path: "eslint.config.mjs",
|
|
293
|
+
content: `import { config } from "@codefast/eslint-config/next";
|
|
294
|
+
/**
|
|
295
|
+
* @see https://eslint.org/docs/latest/use/configure/configuration-files
|
|
296
|
+
* @type {import('eslint').Linter.Config[]}
|
|
297
|
+
*/
|
|
298
|
+
const eslintConfig = [...config];
|
|
299
|
+
|
|
300
|
+
export default eslintConfig;
|
|
301
|
+
`,
|
|
302
|
+
description: "ESLint configuration for the project"
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
path: "lint-staged.config.mjs",
|
|
306
|
+
content: `import { relative } from "node:path";
|
|
177
307
|
/**
|
|
178
308
|
* Builds an ESLint command with the given filenames.
|
|
179
309
|
*
|
|
@@ -197,16 +327,13 @@ const config = {
|
|
|
197
327
|
|
|
198
328
|
export default config;
|
|
199
329
|
`,
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
export default eslintConfig;
|
|
208
|
-
`,
|
|
209
|
-
"src/lib/fonts.ts": `import { cn } from "@codefast/ui";
|
|
330
|
+
description: "Configure lint-staged for pre-commit checks"
|
|
331
|
+
}
|
|
332
|
+
],
|
|
333
|
+
styles: [
|
|
334
|
+
{
|
|
335
|
+
path: "src/lib/fonts.ts",
|
|
336
|
+
content: `import { cn } from "@codefast/ui";
|
|
210
337
|
import { Geist, Geist_Mono as GeistMono } from "next/font/google";
|
|
211
338
|
|
|
212
339
|
const fontGeistSans = Geist({
|
|
@@ -221,7 +348,11 @@ const fontGeistMono = GeistMono({
|
|
|
221
348
|
|
|
222
349
|
export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
|
|
223
350
|
`,
|
|
224
|
-
|
|
351
|
+
description: "Font configuration for the application"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
path: "src/app/globals.css",
|
|
355
|
+
content: `@import "tailwindcss";
|
|
225
356
|
|
|
226
357
|
@import "@codefast/ui/styles.css";
|
|
227
358
|
|
|
@@ -229,103 +360,71 @@ export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
|
|
|
229
360
|
|
|
230
361
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
231
362
|
|
|
232
|
-
@theme inline {
|
|
233
|
-
--font-sans: var(--font-geist-sans);
|
|
234
|
-
--font-mono: var(--font-geist-mono);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
363
|
@layer base {
|
|
238
364
|
:root {
|
|
365
|
+
--font-sans: var(--font-geist-sans);
|
|
366
|
+
--font-mono: var(--font-geist-mono);
|
|
239
367
|
--input: var(--color-neutral-200);
|
|
240
368
|
--border: var(--color-neutral-200);
|
|
241
|
-
|
|
242
369
|
--ring: var(--color-neutral-400);
|
|
243
|
-
|
|
244
370
|
--background: var(--color-white);
|
|
245
371
|
--foreground: var(--color-neutral-950);
|
|
246
|
-
|
|
247
372
|
--primary: var(--color-sky-500);
|
|
248
373
|
--primary-foreground: var(--color-neutral-50);
|
|
249
|
-
|
|
250
374
|
--secondary: var(--color-neutral-100);
|
|
251
375
|
--secondary-foreground: var(--color-neutral-900);
|
|
252
|
-
|
|
253
376
|
--destructive: var(--color-red-600);
|
|
254
|
-
|
|
255
377
|
--accent: var(--color-neutral-100);
|
|
256
378
|
--accent-foreground: var(--color-neutral-900);
|
|
257
|
-
|
|
258
379
|
--muted: var(--color-neutral-100);
|
|
259
380
|
--muted-foreground: var(--color-neutral-500);
|
|
260
|
-
|
|
261
381
|
--popover: var(--color-white);
|
|
262
382
|
--popover-foreground: var(--color-neutral-950);
|
|
263
383
|
--popover-overlay: --alpha(var(--color-neutral-900) / 20%);
|
|
264
|
-
|
|
265
384
|
--card: var(--color-white);
|
|
266
385
|
--card-foreground: var(--color-neutral-950);
|
|
267
|
-
|
|
268
386
|
--sidebar: var(--color-neutral-50);
|
|
269
387
|
--sidebar-foreground: var(--color-neutral-950);
|
|
270
|
-
|
|
271
388
|
--sidebar-primary: var(--color-sky-500);
|
|
272
389
|
--sidebar-primary-foreground: var(--color-neutral-50);
|
|
273
|
-
|
|
274
390
|
--sidebar-accent: var(--color-neutral-100);
|
|
275
391
|
--sidebar-accent-foreground: var(--color-neutral-900);
|
|
276
|
-
|
|
277
392
|
--sidebar-border: var(--color-neutral-200);
|
|
278
393
|
--sidebar-ring: var(--color-neutral-400);
|
|
279
|
-
|
|
280
394
|
--chart-1: var(--color-orange-600);
|
|
281
395
|
--chart-2: var(--color-teal-600);
|
|
282
396
|
--chart-3: var(--color-cyan-600);
|
|
283
397
|
--chart-4: var(--color-amber-600);
|
|
284
398
|
--chart-5: var(--color-amber-500);
|
|
285
399
|
}
|
|
286
|
-
|
|
287
400
|
@variant dark {
|
|
288
401
|
--input: var(--color-neutral-700);
|
|
289
402
|
--border: --alpha(var(--color-neutral-700) / 50%);
|
|
290
|
-
|
|
291
403
|
--ring: var(--color-neutral-500);
|
|
292
|
-
|
|
293
404
|
--background: var(--color-neutral-950);
|
|
294
405
|
--foreground: var(--color-neutral-50);
|
|
295
|
-
|
|
296
406
|
--primary: var(--color-sky-700);
|
|
297
407
|
--primary-foreground: var(--color-neutral-50);
|
|
298
|
-
|
|
299
408
|
--secondary: var(--color-neutral-800);
|
|
300
409
|
--secondary-foreground: var(--color-neutral-50);
|
|
301
|
-
|
|
302
410
|
--destructive: var(--color-red-400);
|
|
303
|
-
|
|
304
411
|
--accent: var(--color-neutral-700);
|
|
305
412
|
--accent-foreground: var(--color-neutral-50);
|
|
306
|
-
|
|
307
413
|
--muted: var(--color-neutral-800);
|
|
308
414
|
--muted-foreground: var(--color-neutral-400);
|
|
309
|
-
|
|
310
415
|
--popover: var(--color-neutral-800);
|
|
311
416
|
--popover-foreground: var(--color-neutral-50);
|
|
312
417
|
--popover-overlay: --alpha(var(--color-neutral-900) / 80%);
|
|
313
|
-
|
|
314
418
|
--card: var(--color-neutral-900);
|
|
315
419
|
--card-foreground: var(--color-neutral-50);
|
|
316
|
-
|
|
317
420
|
--sidebar: var(--color-neutral-900);
|
|
318
421
|
--sidebar-foreground: var(--color-neutral-50);
|
|
319
|
-
|
|
320
422
|
--sidebar-primary: var(--color-sky-700);
|
|
321
423
|
--sidebar-primary-foreground: var(--color-neutral-50);
|
|
322
|
-
|
|
323
424
|
--sidebar-accent: var(--color-neutral-800);
|
|
324
425
|
--sidebar-accent-foreground: var(--color-neutral-50);
|
|
325
|
-
|
|
326
426
|
--sidebar-border: var(--color-neutral-800);
|
|
327
427
|
--sidebar-ring: var(--color-neutral-600);
|
|
328
|
-
|
|
329
428
|
--chart-1: var(--color-blue-700);
|
|
330
429
|
--chart-2: var(--color-emerald-500);
|
|
331
430
|
--chart-3: var(--color-amber-500);
|
|
@@ -333,82 +432,164 @@ export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
|
|
|
333
432
|
--chart-5: var(--color-rose-500);
|
|
334
433
|
}
|
|
335
434
|
}
|
|
336
|
-
|
|
435
|
+
`,
|
|
436
|
+
description: "Global CSS variables for the application"
|
|
437
|
+
}
|
|
438
|
+
]
|
|
337
439
|
};
|
|
440
|
+
function updatePostcssConfig(projectDir) {
|
|
441
|
+
const postcssConfigPath = external_node_path_default().join(projectDir, "postcss.config.mjs");
|
|
442
|
+
if (!external_node_fs_default().existsSync(postcssConfigPath)) return void console.warn(`⚠️ postcss.config.mjs not found, skipping update.`);
|
|
443
|
+
let content = external_node_fs_default().readFileSync(postcssConfigPath, "utf8");
|
|
444
|
+
const typeComment = `/** @type {import('postcss-load-config').Config} */\n`;
|
|
445
|
+
if (content.includes(typeComment)) console.log(`📝 postcss.config.mjs already contains type comment, no changes made.`);
|
|
446
|
+
else {
|
|
447
|
+
content = content.replace("const config = {", `${typeComment}const config = {`);
|
|
448
|
+
external_node_fs_default().writeFileSync(postcssConfigPath, content);
|
|
449
|
+
console.log(`📝 Updated postcss.config.mjs with type comment.`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function updateLayoutFile(projectDir) {
|
|
453
|
+
const layoutPath = external_node_path_default().join(projectDir, "src/app/layout.tsx");
|
|
454
|
+
if (!external_node_fs_default().existsSync(layoutPath)) return void console.warn(`⚠️ src/app/layout.tsx not found, skipping update.`);
|
|
455
|
+
let content = external_node_fs_default().readFileSync(layoutPath, "utf8");
|
|
456
|
+
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.`);
|
|
457
|
+
const newImports = `import type { Metadata } from "next";
|
|
458
|
+
|
|
459
|
+
import { cn } from "@codefast/ui";
|
|
460
|
+
|
|
461
|
+
import { fontVariables } from "@/lib/fonts";
|
|
462
|
+
import "@/app/globals.css";`;
|
|
463
|
+
content = content.replaceAll(/import\s+{[^}]+}\s+from\s+["']next\/font\/google["'];\s*/g, "");
|
|
464
|
+
content = content.replace(/const\s+geistSans\s*=[^;]+;\s*const\s+geistMono\s*=[^;]+;\s*/, "");
|
|
465
|
+
content = content.replace(/import\s+type\s+{[^}]+}\s+from\s+["']next["'];\s*import\s+["']\.\/globals\.css["'];\s*/, newImports);
|
|
466
|
+
const htmlRegex = /<html\s+lang="en"\s*>/;
|
|
467
|
+
const newHtml = '<html className={cn(fontVariables, "antialiased")} lang="en">';
|
|
468
|
+
content = content.replace(htmlRegex, newHtml);
|
|
469
|
+
const bodyRegex = /<body\s+className={`[^`]*`}\s*>/;
|
|
470
|
+
const newBody = "<body>";
|
|
471
|
+
content = content.replace(bodyRegex, newBody);
|
|
472
|
+
try {
|
|
473
|
+
external_node_fs_default().writeFileSync(layoutPath, content);
|
|
474
|
+
console.log(`📝 Updated src/app/layout.tsx to use fontVariables in html tag and removed className from body`);
|
|
475
|
+
} catch (error) {
|
|
476
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
477
|
+
console.warn(`⚠️ Failed to update src/app/layout.tsx: ${errorMessage}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
338
480
|
function updatePackageJson(projectDir) {
|
|
339
|
-
const packageJsonPath =
|
|
340
|
-
const packageJson = JSON.parse(
|
|
481
|
+
const packageJsonPath = external_node_path_default().join(projectDir, "package.json");
|
|
482
|
+
const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, "utf8"));
|
|
341
483
|
packageJson.scripts = {
|
|
342
484
|
...packageJson.scripts,
|
|
485
|
+
"deploy:preview": "vercel deploy --archive=tgz",
|
|
486
|
+
"deploy:prod": "vercel deploy --archive=tgz --prod",
|
|
343
487
|
format: 'prettier --write "**/*.{js,mjs,jsx,ts,tsx,json,css,md,mdx}"',
|
|
344
488
|
"format:check": 'prettier --check "**/*.{js,mjs,jsx,ts,tsx,json,css,md,mdx}"',
|
|
345
|
-
|
|
489
|
+
lint: "next lint --fix --max-warnings 0",
|
|
490
|
+
"lint:check": "next lint --max-warnings 0",
|
|
491
|
+
"package:install": "pnpm install",
|
|
492
|
+
"package:outdated": "pnpm outdated",
|
|
493
|
+
"package:upgrade": "pnpm update --latest",
|
|
494
|
+
preview: "pnpm build && pnpm start"
|
|
346
495
|
};
|
|
347
496
|
packageJson["simple-git-hooks"] = {
|
|
348
497
|
"pre-commit": "pnpm lint-staged",
|
|
349
498
|
"commit-msg": "pnpm commitlint --edit"
|
|
350
499
|
};
|
|
351
|
-
|
|
352
|
-
console.log(
|
|
500
|
+
external_node_fs_default().writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
501
|
+
console.log(`📝 Updated package.json`);
|
|
353
502
|
}
|
|
354
|
-
function
|
|
355
|
-
console.log(
|
|
356
|
-
const
|
|
357
|
-
|
|
503
|
+
function createConfigFiles(projectDir) {
|
|
504
|
+
console.log(`\n📝 Creating configuration files...`);
|
|
505
|
+
for (const [category, configs] of Object.entries(configGroups)){
|
|
506
|
+
console.log(`\n📂 Setting up ${category} configurations:`);
|
|
507
|
+
for (const { path: filePath, content, description } of configs){
|
|
508
|
+
const fullPath = external_node_path_default().join(projectDir, filePath);
|
|
509
|
+
const dir = external_node_path_default().dirname(fullPath);
|
|
510
|
+
if (!external_node_fs_default().existsSync(dir)) external_node_fs_default().mkdirSync(dir, {
|
|
511
|
+
recursive: true
|
|
512
|
+
});
|
|
513
|
+
writeConfigFile(fullPath, content);
|
|
514
|
+
if (description) console.log(` ℹ️ ${filePath}: ${description}`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
358
517
|
}
|
|
359
518
|
function installDependencies() {
|
|
360
|
-
console.log(
|
|
519
|
+
console.log(`\n📚 Installing dependencies...`);
|
|
361
520
|
if (MAIN_DEPENDENCIES.length > 0) runCommand(`pnpm add ${MAIN_DEPENDENCIES.join(" ")}`);
|
|
362
521
|
const allDevDependencies = Object.values(DEV_DEPENDENCIES).flat().join(" ");
|
|
363
522
|
if (allDevDependencies) runCommand(`pnpm add -D ${allDevDependencies}`);
|
|
364
523
|
}
|
|
365
|
-
function
|
|
366
|
-
console.log(`\n
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
524
|
+
function cleanupPackages() {
|
|
525
|
+
console.log(`\n🧹 Cleaning up unnecessary packages...`);
|
|
526
|
+
const packageJsonPath = external_node_path_namespaceObject.join(process.cwd(), "package.json");
|
|
527
|
+
if (!external_node_fs_namespaceObject.existsSync(packageJsonPath)) return void console.warn(`⚠️ package.json not found, skipping cleanup.`);
|
|
528
|
+
let packageJson;
|
|
529
|
+
try {
|
|
530
|
+
packageJson = JSON.parse(external_node_fs_namespaceObject.readFileSync(packageJsonPath, "utf8"));
|
|
531
|
+
} catch (error) {
|
|
532
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
533
|
+
console.warn(`⚠️ Error reading package.json: ${errorMessage}, skipping cleanup.`);
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
const dependencies = packageJson.dependencies ?? {};
|
|
537
|
+
const devDependencies = packageJson.devDependencies ?? {};
|
|
538
|
+
const packagesToRemove = PACKAGES_TO_REMOVE.filter((pkg)=>pkg in dependencies || pkg in devDependencies);
|
|
539
|
+
if (packagesToRemove.length > 0) runCommand(`pnpm remove ${packagesToRemove.join(" ")}`);
|
|
540
|
+
else console.log(`ℹ️ No unnecessary packages found in package.json to remove.`);
|
|
541
|
+
}
|
|
542
|
+
function checkEnvironment() {
|
|
543
|
+
try {
|
|
544
|
+
(0, external_node_child_process_namespaceObject.execSync)("pnpm --version", {
|
|
545
|
+
stdio: "ignore"
|
|
372
546
|
});
|
|
373
|
-
|
|
547
|
+
} catch {
|
|
548
|
+
console.error(`❌ PNPM chưa được cài đặt. Vui lòng cài đặt PNPM trước.`);
|
|
549
|
+
process.exit(1);
|
|
374
550
|
}
|
|
375
551
|
}
|
|
552
|
+
function createNextProject(projectName) {
|
|
553
|
+
console.log(`📦 Creating Next.js project...`);
|
|
554
|
+
const flags = '--ts --tailwind --eslint --app --turbo --use-pnpm --src-dir --turbopack --import-alias "@/*"';
|
|
555
|
+
runCommand(`npx create-next-app@latest ${projectName} ${flags}`);
|
|
556
|
+
}
|
|
376
557
|
function createProjectCommand(program) {
|
|
377
558
|
program.command("create-project [name]").description("Create a new Next.js project with recommended setup").action(async (projectNameArg)=>{
|
|
378
559
|
try {
|
|
379
560
|
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 {
|
|
561
|
+
const { projectName, packageJsonExists } = await checkExistingProject(projectNameArg);
|
|
562
|
+
if (!packageJsonExists) {
|
|
563
|
+
console.log(`\n🚀 Starting project creation for ${projectName}...\n`);
|
|
385
564
|
createNextProject(projectName);
|
|
386
565
|
process.chdir(projectName);
|
|
387
566
|
console.log(`📂 Moved to ${projectName}`);
|
|
388
567
|
}
|
|
568
|
+
updateLayoutFile(process.cwd());
|
|
389
569
|
updatePostcssConfig(process.cwd());
|
|
390
570
|
installDependencies();
|
|
571
|
+
cleanupPackages();
|
|
391
572
|
createConfigFiles(process.cwd());
|
|
392
573
|
updatePackageJson(process.cwd());
|
|
393
574
|
console.log(`\n🔄 Activating git hooks...`);
|
|
394
575
|
runCommand("pnpm simple-git-hooks");
|
|
395
576
|
console.log(`\n📝 Formatting files with Prettier...`);
|
|
396
577
|
runCommand("pnpm format");
|
|
397
|
-
console.log(`\n✅ Project created successfully!`);
|
|
578
|
+
console.log(`\n✅ Project ${packageJsonExists ? "configured" : "created"} successfully!`);
|
|
398
579
|
console.log(`- Project: ${projectName}`);
|
|
399
580
|
console.log("- Next.js with TypeScript");
|
|
400
581
|
console.log("- TailwindCSS and @codefast/ui");
|
|
401
582
|
console.log("- ESLint, Prettier, Commitlint, and Git Hooks");
|
|
402
583
|
console.log("- Lint-staged for pre-commit checks");
|
|
403
|
-
console.log(`\n📁 Project directory: ${
|
|
584
|
+
console.log(`\n📁 Project directory: ${process.cwd()}`);
|
|
404
585
|
console.log(`\n🚀 To start development:`);
|
|
405
586
|
console.log(`cd ${projectName} && pnpm dev`);
|
|
406
|
-
rl.close();
|
|
407
587
|
} catch (error) {
|
|
408
588
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
409
589
|
console.error(`\n❌ An error occurred: ${errorMessage}`);
|
|
410
|
-
rl.close();
|
|
411
590
|
process.exit(1);
|
|
591
|
+
} finally{
|
|
592
|
+
rl.close();
|
|
412
593
|
}
|
|
413
594
|
});
|
|
414
595
|
}
|