@codefast/cli 0.3.1-canary.4 โ 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 +26 -0
- package/dist/index.cjs +474 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +472 -56
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
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
|
+
|
|
15
|
+
## 0.3.1-canary.5
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [`f5b9777`](https://github.com/codefastlabs/codefast/commit/f5b977794956920183e2b132633e61cac4be4fdb) Thanks [@thevuong](https://github.com/thevuong)! - feat(cli): skip Next.js project creation if package.json exists
|
|
20
|
+
|
|
21
|
+
- [`77ccc05`](https://github.com/codefastlabs/codefast/commit/77ccc0556a1da4ee934af56fe8aef66eec0e1cf0) Thanks [@thevuong](https://github.com/thevuong)! - feat: support optional values in change handlers
|
|
22
|
+
|
|
23
|
+
- [`876c1cb`](https://github.com/codefastlabs/codefast/commit/876c1cb7d7ff7691096da7cc19faa44ddcffea70) Thanks [@thevuong](https://github.com/thevuong)! - refactor(cli): remove logger utility and update logging usage
|
|
24
|
+
|
|
25
|
+
- [`9e7aa7c`](https://github.com/codefastlabs/codefast/commit/9e7aa7c40e8d68257fbcd62ddb8fc7e2f6fcc895) Thanks [@thevuong](https://github.com/thevuong)! - chore(dependencies): update dependencies to latest versions
|
|
26
|
+
|
|
27
|
+
- [`80bd1ad`](https://github.com/codefastlabs/codefast/commit/80bd1ad5282d489b2da9f84d373adc40a9b24dc2) Thanks [@thevuong](https://github.com/thevuong)! - feat(cli): add enhanced project creation command
|
|
28
|
+
|
|
3
29
|
## 0.3.1-canary.4
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -26,9 +26,455 @@ var __webpack_require__ = {};
|
|
|
26
26
|
})();
|
|
27
27
|
var __webpack_exports__ = {};
|
|
28
28
|
const external_commander_namespaceObject = require("commander");
|
|
29
|
-
const
|
|
29
|
+
const external_node_fs_namespaceObject = require("node:fs");
|
|
30
|
+
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
30
31
|
const external_node_path_namespaceObject = require("node:path");
|
|
31
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
|
+
const external_node_readline_namespaceObject = require("node:readline");
|
|
35
|
+
var external_node_readline_default = /*#__PURE__*/ __webpack_require__.n(external_node_readline_namespaceObject);
|
|
36
|
+
const rl = external_node_readline_default().createInterface({
|
|
37
|
+
input: process.stdin,
|
|
38
|
+
output: process.stdout
|
|
39
|
+
});
|
|
40
|
+
function utils_prompt(question) {
|
|
41
|
+
return new Promise((resolve)=>{
|
|
42
|
+
rl.question(question, (answer)=>{
|
|
43
|
+
resolve(answer.trim());
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
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}`);
|
|
55
|
+
}
|
|
56
|
+
function validateProjectName(name) {
|
|
57
|
+
if (!name || /^\s*$/.test(name)) return {
|
|
58
|
+
valid: false,
|
|
59
|
+
error: "Project name cannot be empty or contain only whitespace."
|
|
60
|
+
};
|
|
61
|
+
if (name.length > 100) return {
|
|
62
|
+
valid: false,
|
|
63
|
+
error: "Project name is too long (maximum 100 characters)."
|
|
64
|
+
};
|
|
65
|
+
const npmNameRegex = /^[a-z0-9-~][a-z0-9-._~]*$/;
|
|
66
|
+
if (!npmNameRegex.test(name)) return {
|
|
67
|
+
valid: false,
|
|
68
|
+
error: "Project name must be URL-friendly (letters, numbers, hyphens, underscores, dots; no @ or scoped packages)."
|
|
69
|
+
};
|
|
70
|
+
if ("." === name || ".." === name) return {
|
|
71
|
+
valid: false,
|
|
72
|
+
error: "Project name cannot be '.' or '..'."
|
|
73
|
+
};
|
|
74
|
+
const reservedNames = /^(?<reserved>CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i;
|
|
75
|
+
if (reservedNames.test(name)) return {
|
|
76
|
+
valid: false,
|
|
77
|
+
error: `Project name "${name}" is a reserved system name.`
|
|
78
|
+
};
|
|
79
|
+
const fullPath = external_node_path_default().resolve(process.cwd(), name);
|
|
80
|
+
if (external_node_fs_default().existsSync(fullPath)) return {
|
|
81
|
+
valid: false,
|
|
82
|
+
error: `A directory named "${name}" already exists.`
|
|
83
|
+
};
|
|
84
|
+
try {
|
|
85
|
+
external_node_fs_default().accessSync(process.cwd(), external_node_fs_default().constants.W_OK);
|
|
86
|
+
} catch {
|
|
87
|
+
return {
|
|
88
|
+
valid: false,
|
|
89
|
+
error: "Cannot create project: No write permission in current directory."
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
valid: true
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function getValidProjectName(initialName, attempts = 0, maxAttempts = 3) {
|
|
97
|
+
const projectName = initialName ?? await utils_prompt("Enter project name: ");
|
|
98
|
+
const validation = validateProjectName(projectName);
|
|
99
|
+
if (validation.valid) return projectName;
|
|
100
|
+
if (attempts >= maxAttempts - 1) throw new Error(`โ Exceeded maximum attempts to enter a valid project name.`);
|
|
101
|
+
console.error(`โ ${validation.error} (${maxAttempts - attempts - 1} attempts remaining)`);
|
|
102
|
+
return getValidProjectName(void 0, attempts + 1, maxAttempts);
|
|
103
|
+
}
|
|
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.");
|
|
120
|
+
}
|
|
121
|
+
const projectName = await getValidProjectName(projectNameArg);
|
|
122
|
+
return {
|
|
123
|
+
projectName,
|
|
124
|
+
packageJsonExists
|
|
125
|
+
};
|
|
126
|
+
}
|
|
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: `/**
|
|
158
|
+
* @see https://commitlint.js.org/reference/configuration.html
|
|
159
|
+
* @type {import('@commitlint/types').UserConfig}
|
|
160
|
+
*/
|
|
161
|
+
const config = {
|
|
162
|
+
extends: ["@commitlint/config-conventional"],
|
|
163
|
+
rules: {
|
|
164
|
+
"body-max-line-length": [2, "always", 350],
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
export default config;
|
|
168
|
+
`,
|
|
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[]}
|
|
177
|
+
*/
|
|
178
|
+
const eslintConfig = [...config];
|
|
179
|
+
export default eslintConfig;
|
|
180
|
+
`,
|
|
181
|
+
description: "ESLint configuration for the project"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
path: "lint-staged.config.mjs",
|
|
185
|
+
content: `import { relative } from "node:path";
|
|
186
|
+
/**
|
|
187
|
+
* Builds an ESLint command with the given filenames.
|
|
188
|
+
*
|
|
189
|
+
* @param {string[]} filenames - An array of filenames to be passed to the
|
|
190
|
+
* ESLint command.
|
|
191
|
+
* @returns {string} - The generated ESLint command.
|
|
192
|
+
*/
|
|
193
|
+
function buildEslintCommand(filenames) {
|
|
194
|
+
return \`next lint --fix --max-warnings 0 --file \${filenames.map((file) => relative(import.meta.dirname, file)).
|
|
195
|
+
join(" --file ")}\`;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* @see https://www.npmjs.com/package/lint-staged
|
|
199
|
+
* @type {import('lint-staged').Configuration}
|
|
200
|
+
*/
|
|
201
|
+
const config = {
|
|
202
|
+
"*.{js,mjs,jsx,ts,tsx}": [buildEslintCommand, "prettier --list-different --write"],
|
|
203
|
+
"*.{json,css,md,mdx}": ["prettier --list-different --write"],
|
|
204
|
+
};
|
|
205
|
+
export default config;
|
|
206
|
+
`,
|
|
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}
|
|
216
|
+
*/
|
|
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;
|
|
224
|
+
`,
|
|
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";
|
|
232
|
+
import { Geist, Geist_Mono as GeistMono } from "next/font/google";
|
|
233
|
+
const fontGeistSans = Geist({
|
|
234
|
+
subsets: ["latin"],
|
|
235
|
+
variable: "--font-geist-sans",
|
|
236
|
+
});
|
|
237
|
+
const fontGeistMono = GeistMono({
|
|
238
|
+
subsets: ["latin"],
|
|
239
|
+
variable: "--font-geist-mono",
|
|
240
|
+
});
|
|
241
|
+
export const fontVariables = cn(fontGeistSans.variable, fontGeistMono.variable);
|
|
242
|
+
`,
|
|
243
|
+
description: "Font configuration for the application"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
path: "src/app/globals.css",
|
|
247
|
+
content: `@import "tailwindcss";
|
|
248
|
+
@import "@codefast/ui/styles.css";
|
|
249
|
+
@source '../../node_modules/@codefast/ui';
|
|
250
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
251
|
+
@layer base {
|
|
252
|
+
:root {
|
|
253
|
+
--font-sans: var(--font-geist-sans);
|
|
254
|
+
--font-mono: var(--font-geist-mono);
|
|
255
|
+
--input: var(--color-neutral-200);
|
|
256
|
+
--border: var(--color-neutral-200);
|
|
257
|
+
--ring: var(--color-neutral-400);
|
|
258
|
+
--background: var(--color-white);
|
|
259
|
+
--foreground: var(--color-neutral-950);
|
|
260
|
+
--primary: var(--color-sky-500);
|
|
261
|
+
--primary-foreground: var(--color-neutral-50);
|
|
262
|
+
--secondary: var(--color-neutral-100);
|
|
263
|
+
--secondary-foreground: var(--color-neutral-900);
|
|
264
|
+
--destructive: var(--color-red-600);
|
|
265
|
+
--accent: var(--color-neutral-100);
|
|
266
|
+
--accent-foreground: var(--color-neutral-900);
|
|
267
|
+
--muted: var(--color-neutral-100);
|
|
268
|
+
--muted-foreground: var(--color-neutral-500);
|
|
269
|
+
--popover: var(--color-white);
|
|
270
|
+
--popover-foreground: var(--color-neutral-950);
|
|
271
|
+
--popover-overlay: --alpha(var(--color-neutral-900) / 20%);
|
|
272
|
+
--card: var(--color-white);
|
|
273
|
+
--card-foreground: var(--color-neutral-950);
|
|
274
|
+
--sidebar: var(--color-neutral-50);
|
|
275
|
+
--sidebar-foreground: var(--color-neutral-950);
|
|
276
|
+
--sidebar-primary: var(--color-sky-500);
|
|
277
|
+
--sidebar-primary-foreground: var(--color-neutral-50);
|
|
278
|
+
--sidebar-accent: var(--color-neutral-100);
|
|
279
|
+
--sidebar-accent-foreground: var(--color-neutral-900);
|
|
280
|
+
--sidebar-border: var(--color-neutral-200);
|
|
281
|
+
--sidebar-ring: var(--color-neutral-400);
|
|
282
|
+
--chart-1: var(--color-orange-600);
|
|
283
|
+
--chart-2: var(--color-teal-600);
|
|
284
|
+
--chart-3: var(--color-cyan-600);
|
|
285
|
+
--chart-4: var(--color-amber-600);
|
|
286
|
+
--chart-5: var(--color-amber-500);
|
|
287
|
+
}
|
|
288
|
+
@variant dark {
|
|
289
|
+
--input: var(--color-neutral-700);
|
|
290
|
+
--border: --alpha(var(--color-neutral-700) / 50%);
|
|
291
|
+
--ring: var(--color-neutral-500);
|
|
292
|
+
--background: var(--color-neutral-950);
|
|
293
|
+
--foreground: var(--color-neutral-50);
|
|
294
|
+
--primary: var(--color-sky-700);
|
|
295
|
+
--primary-foreground: var(--color-neutral-50);
|
|
296
|
+
--secondary: var(--color-neutral-800);
|
|
297
|
+
--secondary-foreground: var(--color-neutral-50);
|
|
298
|
+
--destructive: var(--color-red-400);
|
|
299
|
+
--accent: var(--color-neutral-700);
|
|
300
|
+
--accent-foreground: var(--color-neutral-50);
|
|
301
|
+
--muted: var(--color-neutral-800);
|
|
302
|
+
--muted-foreground: var(--color-neutral-400);
|
|
303
|
+
--popover: var(--color-neutral-800);
|
|
304
|
+
--popover-foreground: var(--color-neutral-50);
|
|
305
|
+
--popover-overlay: --alpha(var(--color-neutral-900) / 80%);
|
|
306
|
+
--card: var(--color-neutral-900);
|
|
307
|
+
--card-foreground: var(--color-neutral-50);
|
|
308
|
+
--sidebar: var(--color-neutral-900);
|
|
309
|
+
--sidebar-foreground: var(--color-neutral-50);
|
|
310
|
+
--sidebar-primary: var(--color-sky-700);
|
|
311
|
+
--sidebar-primary-foreground: var(--color-neutral-50);
|
|
312
|
+
--sidebar-accent: var(--color-neutral-800);
|
|
313
|
+
--sidebar-accent-foreground: var(--color-neutral-50);
|
|
314
|
+
--sidebar-border: var(--color-neutral-800);
|
|
315
|
+
--sidebar-ring: var(--color-neutral-600);
|
|
316
|
+
--chart-1: var(--color-blue-700);
|
|
317
|
+
--chart-2: var(--color-emerald-500);
|
|
318
|
+
--chart-3: var(--color-amber-500);
|
|
319
|
+
--chart-4: var(--color-purple-500);
|
|
320
|
+
--chart-5: var(--color-rose-500);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
`,
|
|
324
|
+
description: "Global CSS variables for the application"
|
|
325
|
+
}
|
|
326
|
+
]
|
|
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
|
+
}
|
|
368
|
+
function updatePackageJson(projectDir) {
|
|
369
|
+
const packageJsonPath = external_node_path_default().join(projectDir, "package.json");
|
|
370
|
+
const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, "utf8"));
|
|
371
|
+
packageJson.scripts = {
|
|
372
|
+
...packageJson.scripts,
|
|
373
|
+
format: 'prettier --write "**/*.{js,mjs,jsx,ts,tsx,json,css,md,mdx}"',
|
|
374
|
+
"format:check": 'prettier --check "**/*.{js,mjs,jsx,ts,tsx,json,css,md,mdx}"',
|
|
375
|
+
"lint:check": "next lint --max-warnings 0"
|
|
376
|
+
};
|
|
377
|
+
packageJson["simple-git-hooks"] = {
|
|
378
|
+
"pre-commit": "pnpm lint-staged",
|
|
379
|
+
"commit-msg": "pnpm commitlint --edit"
|
|
380
|
+
};
|
|
381
|
+
external_node_fs_default().writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
382
|
+
console.log(`๐ Updated package.json`);
|
|
383
|
+
}
|
|
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
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function installDependencies() {
|
|
400
|
+
console.log(`\n๐ Installing dependencies...`);
|
|
401
|
+
if (MAIN_DEPENDENCIES.length > 0) runCommand(`pnpm add ${MAIN_DEPENDENCIES.join(" ")}`);
|
|
402
|
+
const allDevDependencies = Object.values(DEV_DEPENDENCIES).flat().join(" ");
|
|
403
|
+
if (allDevDependencies) runCommand(`pnpm add -D ${allDevDependencies}`);
|
|
404
|
+
}
|
|
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"
|
|
427
|
+
});
|
|
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);
|
|
431
|
+
}
|
|
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
|
+
}
|
|
438
|
+
function createProjectCommand(program) {
|
|
439
|
+
program.command("create-project [name]").description("Create a new Next.js project with recommended setup").action(async (projectNameArg)=>{
|
|
440
|
+
try {
|
|
441
|
+
checkEnvironment();
|
|
442
|
+
const { projectName, packageJsonExists } = await checkExistingProject(projectNameArg);
|
|
443
|
+
if (!packageJsonExists) {
|
|
444
|
+
console.log(`\n๐ Starting project creation for ${projectName}...\n`);
|
|
445
|
+
createNextProject(projectName);
|
|
446
|
+
process.chdir(projectName);
|
|
447
|
+
console.log(`๐ Moved to ${projectName}`);
|
|
448
|
+
}
|
|
449
|
+
updateLayoutFile(process.cwd());
|
|
450
|
+
updatePostcssConfig(process.cwd());
|
|
451
|
+
installDependencies();
|
|
452
|
+
cleanupPackages();
|
|
453
|
+
createConfigFiles(process.cwd());
|
|
454
|
+
updatePackageJson(process.cwd());
|
|
455
|
+
console.log(`\n๐ Activating git hooks...`);
|
|
456
|
+
runCommand("pnpm simple-git-hooks");
|
|
457
|
+
console.log(`\n๐ Formatting files with Prettier...`);
|
|
458
|
+
runCommand("pnpm format");
|
|
459
|
+
console.log(`\nโ
Project ${packageJsonExists ? "configured" : "created"} successfully!`);
|
|
460
|
+
console.log(`- Project: ${projectName}`);
|
|
461
|
+
console.log("- Next.js with TypeScript");
|
|
462
|
+
console.log("- TailwindCSS and @codefast/ui");
|
|
463
|
+
console.log("- ESLint, Prettier, Commitlint, and Git Hooks");
|
|
464
|
+
console.log("- Lint-staged for pre-commit checks");
|
|
465
|
+
console.log(`\n๐ Project directory: ${process.cwd()}`);
|
|
466
|
+
console.log(`\n๐ To start development:`);
|
|
467
|
+
console.log(`cd ${projectName} && pnpm dev`);
|
|
468
|
+
} catch (error) {
|
|
469
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
470
|
+
console.error(`\nโ An error occurred: ${errorMessage}`);
|
|
471
|
+
process.exit(1);
|
|
472
|
+
} finally{
|
|
473
|
+
rl.close();
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
const external_glob_namespaceObject = require("glob");
|
|
32
478
|
const external_ts_morph_namespaceObject = require("ts-morph");
|
|
33
479
|
function makeRegexPrefixesToRemove(prefixes) {
|
|
34
480
|
const prefixPattern = prefixes.join("|");
|
|
@@ -85,8 +531,6 @@ function analyzeImports(indexFilePath, packageConfig) {
|
|
|
85
531
|
};
|
|
86
532
|
}
|
|
87
533
|
const external_lodash_es_namespaceObject = require("lodash-es");
|
|
88
|
-
const external_node_fs_namespaceObject = require("node:fs");
|
|
89
|
-
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
90
534
|
const external_zod_namespaceObject = require("zod");
|
|
91
535
|
const PackageConfigSchema = external_zod_namespaceObject.z["interface"]({
|
|
92
536
|
cjsOutputPattern: external_zod_namespaceObject.z.string(),
|
|
@@ -280,122 +724,92 @@ async function findAllPackages(config) {
|
|
|
280
724
|
ignore: DEFAULT_IGNORE_PATTERN
|
|
281
725
|
});
|
|
282
726
|
}
|
|
283
|
-
function processPackage(packageJsonPath, options
|
|
727
|
+
function processPackage(packageJsonPath, options) {
|
|
284
728
|
const packageDir = external_node_path_default().dirname(packageJsonPath);
|
|
285
729
|
const packageJson = readPackageJson(packageJsonPath);
|
|
286
730
|
if (!packageJson) {
|
|
287
|
-
|
|
731
|
+
console.error(`Failed to read ${packageJsonPath}`);
|
|
288
732
|
return false;
|
|
289
733
|
}
|
|
290
734
|
const packageName = packageJson.name;
|
|
291
735
|
if (options.packageFilter && packageName !== options.packageFilter) {
|
|
292
|
-
|
|
736
|
+
console.debug(`Skipping ${packageName} (does not match filter)`);
|
|
293
737
|
return false;
|
|
294
738
|
}
|
|
295
|
-
|
|
739
|
+
console.info(`Processing package: ${packageName}`);
|
|
296
740
|
const config = getConfig(options.configPath);
|
|
297
741
|
const packageConfig = getPackageConfig(packageName, config);
|
|
298
742
|
const srcIndexPath = external_node_path_default().join(packageDir, packageConfig.srcIndexPath);
|
|
299
743
|
if (!fileExists(srcIndexPath)) {
|
|
300
|
-
|
|
744
|
+
console.error(`Source file not found at ${srcIndexPath}`);
|
|
301
745
|
return false;
|
|
302
746
|
}
|
|
303
|
-
|
|
747
|
+
console.info(`Analyzing imports from ${srcIndexPath}...`);
|
|
304
748
|
const { imports } = analyzeImports(srcIndexPath, packageConfig);
|
|
305
749
|
if (0 === imports.length) {
|
|
306
|
-
|
|
750
|
+
console.warn(`No imports found to analyze in ${packageName}`);
|
|
307
751
|
return false;
|
|
308
752
|
}
|
|
309
|
-
|
|
753
|
+
console.log(`Analysis complete. Found ${imports.length} subpath exports.`);
|
|
310
754
|
saveExportsAnalysis(packageDir, {
|
|
311
755
|
imports
|
|
312
756
|
});
|
|
313
757
|
const newExports = generateExports(packageName, imports, packageJson.exports, config);
|
|
314
758
|
const currentExportsCount = packageJson.exports ? Object.keys(packageJson.exports).length : 0;
|
|
315
759
|
const newExportsCount = Object.keys(newExports).length;
|
|
316
|
-
|
|
760
|
+
console.info(`Exports: ${currentExportsCount} -> ${newExportsCount}`);
|
|
317
761
|
if (options.dryRun) {
|
|
318
762
|
saveExportsPreview(packageDir, newExports);
|
|
319
|
-
|
|
320
|
-
|
|
763
|
+
console.warn("Saved exports preview to .exports-analysis");
|
|
764
|
+
console.warn(`Dry run: no changes saved for ${packageName}`);
|
|
321
765
|
return true;
|
|
322
766
|
}
|
|
323
|
-
if (backupPackageJson(packageJsonPath))
|
|
767
|
+
if (backupPackageJson(packageJsonPath)) console.log(`Backed up ${packageJsonPath}`);
|
|
324
768
|
const updatedPackageJson = {
|
|
325
769
|
...packageJson,
|
|
326
770
|
exports: newExports
|
|
327
771
|
};
|
|
328
772
|
if (savePackageJson(packageJsonPath, updatedPackageJson)) {
|
|
329
|
-
|
|
773
|
+
console.log(`Updated exports for ${packageName}`);
|
|
330
774
|
return true;
|
|
331
775
|
}
|
|
332
|
-
|
|
776
|
+
console.error(`Failed to update ${packageJsonPath}`);
|
|
333
777
|
return false;
|
|
334
778
|
}
|
|
335
|
-
async function processAllPackages(options
|
|
779
|
+
async function processAllPackages(options) {
|
|
336
780
|
try {
|
|
337
|
-
|
|
781
|
+
console.info("Searching for packages...");
|
|
338
782
|
const config = getConfig(options.configPath);
|
|
339
783
|
const packageJsonPaths = await findAllPackages(config);
|
|
340
|
-
if (0 === packageJsonPaths.length) return void
|
|
341
|
-
|
|
784
|
+
if (0 === packageJsonPaths.length) return void console.warn("No packages found.");
|
|
785
|
+
console.log(`Found ${packageJsonPaths.length} packages.`);
|
|
342
786
|
let successCount = 0;
|
|
343
787
|
let skipCount = 0;
|
|
344
788
|
let errorCount = 0;
|
|
345
789
|
for (const packageJsonPath of packageJsonPaths){
|
|
346
|
-
const result = processPackage(packageJsonPath, options
|
|
790
|
+
const result = processPackage(packageJsonPath, options);
|
|
347
791
|
if (result) successCount++;
|
|
348
792
|
else if (options.packageFilter) skipCount++;
|
|
349
793
|
else errorCount++;
|
|
350
794
|
}
|
|
351
|
-
|
|
352
|
-
|
|
795
|
+
console.log("Completed exports update.");
|
|
796
|
+
console.info(`Stats: ${successCount} succeeded, ${skipCount} skipped, ${errorCount} failed`);
|
|
353
797
|
} catch (error) {
|
|
354
|
-
|
|
798
|
+
console.error("Error processing packages:", error);
|
|
355
799
|
throw error;
|
|
356
800
|
}
|
|
357
801
|
}
|
|
358
|
-
const external_chalk_namespaceObject = require("chalk");
|
|
359
|
-
var external_chalk_default = /*#__PURE__*/ __webpack_require__.n(external_chalk_namespaceObject);
|
|
360
|
-
class Logger {
|
|
361
|
-
verbose;
|
|
362
|
-
constructor(options = {}){
|
|
363
|
-
this.verbose = options.verbose ?? false;
|
|
364
|
-
}
|
|
365
|
-
info(message, ...args) {
|
|
366
|
-
console.log(external_chalk_default().blue(message), ...args);
|
|
367
|
-
}
|
|
368
|
-
success(message, ...args) {
|
|
369
|
-
console.log(external_chalk_default().green(message), ...args);
|
|
370
|
-
}
|
|
371
|
-
warn(message, ...args) {
|
|
372
|
-
console.log(external_chalk_default().yellow(message), ...args);
|
|
373
|
-
}
|
|
374
|
-
error(message, ...args) {
|
|
375
|
-
console.error(external_chalk_default().red(message), ...args);
|
|
376
|
-
}
|
|
377
|
-
debug(message, ...args) {
|
|
378
|
-
if (this.verbose) console.log(external_chalk_default().gray(message), ...args);
|
|
379
|
-
}
|
|
380
|
-
table(data) {
|
|
381
|
-
console.table(data);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
802
|
function createUpdateExportsCommand(program) {
|
|
385
|
-
program.command("update-exports").description("Updates exports for all packages").option("-p, --package <package>", "Filter by package name").option("-d, --dry-run", "Run without making changes").option("-
|
|
803
|
+
program.command("update-exports").description("Updates exports for all packages").option("-p, --package <package>", "Filter by package name").option("-d, --dry-run", "Run without making changes").option("-c, --config <path>", "Path to configuration file").action(async (options)=>{
|
|
386
804
|
const processorOptions = {
|
|
387
805
|
packageFilter: options.package,
|
|
388
806
|
dryRun: Boolean(options.dryRun),
|
|
389
|
-
verbose: Boolean(options.verbose),
|
|
390
807
|
configPath: options.config
|
|
391
808
|
};
|
|
392
|
-
const logger = new Logger({
|
|
393
|
-
verbose: processorOptions.verbose
|
|
394
|
-
});
|
|
395
809
|
try {
|
|
396
|
-
await processAllPackages(processorOptions
|
|
810
|
+
await processAllPackages(processorOptions);
|
|
397
811
|
} catch (error) {
|
|
398
|
-
|
|
812
|
+
console.error("Error processing packages:", error);
|
|
399
813
|
process.exit(1);
|
|
400
814
|
}
|
|
401
815
|
});
|
|
@@ -414,7 +828,9 @@ function main() {
|
|
|
414
828
|
const program = new external_commander_namespaceObject.Command();
|
|
415
829
|
program.name("codefast").description("CodeFast CLI - A development toolkit for CodeFast.").version(getPackageVersion(), "-v, --version", "display CLI version");
|
|
416
830
|
createUpdateExportsCommand(program);
|
|
831
|
+
createProjectCommand(program);
|
|
417
832
|
program.action(()=>{
|
|
833
|
+
console.log('Use "codefast create-project" to create a new Next.js project.');
|
|
418
834
|
console.log('Use "codefast update-exports" to update exports.');
|
|
419
835
|
console.log('Run "codefast --help" to see all available commands.');
|
|
420
836
|
program.help();
|