create-next-pro-cli 0.1.13 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/bin.ts +0 -0
- package/install.sh +1 -0
- package/package.json +6 -4
- package/src/index.ts +0 -67
- package/src/lib/addComponent.ts +0 -139
- package/src/lib/addPage.ts +0 -201
- package/src/lib/createProject.ts +0 -18
- package/src/lib/createProjectWithPrompt.ts +0 -79
- package/src/lib/rmPage.ts +0 -52
- package/src/lib/utils.test.ts +0 -23
- package/src/lib/utils.ts +0 -60
- package/src/scaffold-dev.ts +0 -89
- package/src/scaffold.ts +0 -86
- package/templates/Projects/default/src/app/[locale]/(public)/Login/page.tsx +0 -6
- package/templates/Projects/default/src/app/[locale]/(public)/Register/page.tsx +0 -6
- package/templates/Projects/default/src/app/[locale]/(public)/_home/loading.tsx +0 -5
- package/templates/Projects/default/src/app/[locale]/(public)/_home/page.tsx +0 -6
- package/templates/Projects/default/src/app/[locale]/(public)/layout.tsx +0 -9
- package/templates/Projects/default/src/app/[locale]/(user)/Dashboard/error.tsx +0 -38
- package/templates/Projects/default/src/app/[locale]/(user)/Dashboard/loading.tsx +0 -10
- package/templates/Projects/default/src/app/[locale]/(user)/Dashboard/page.tsx +0 -5
- package/templates/Projects/default/src/app/[locale]/(user)/Settings/loading.tsx +0 -17
- package/templates/Projects/default/src/app/[locale]/(user)/Settings/page.tsx +0 -6
- package/templates/Projects/default/src/app/[locale]/(user)/UserInfo/loading.tsx +0 -17
- package/templates/Projects/default/src/app/[locale]/(user)/UserInfo/page.tsx +0 -6
- package/templates/Projects/default/src/app/[locale]/(user)/layout.tsx +0 -9
- package/templates/Projects/default/src/app/[locale]/layout.tsx +0 -31
- package/templates/Projects/default/src/app/[locale]/loading.tsx +0 -14
- package/templates/Projects/default/src/app/[locale]/not-found.tsx +0 -22
- package/templates/Projects/default/src/app/[locale]/page.tsx +0 -6
- package/templates/Projects/default/src/app/api/auth/[...nextauth]/route.ts +0 -62
- package/templates/Projects/default/src/app/api/auth/post-login/route.ts +0 -26
- package/templates/Projects/default/src/app/favicon.ico +0 -0
- package/templates/Projects/default/src/app/layout.tsx +0 -11
- package/templates/Projects/default/src/app/not-found.tsx +0 -17
- package/templates/Projects/default/src/app/page.tsx +0 -6
- package/templates/Projects/default/src/app/sitemap.ts +0 -27
- package/templates/Projects/default/src/app/styles/globals.css +0 -305
- package/templates/Projects/default/src/auth.config.ts +0 -0
- package/templates/Projects/default/src/config.ts +0 -4
- package/templates/Projects/default/src/lib/auth/disconnect.ts +0 -11
- package/templates/Projects/default/src/lib/auth/isConnected.ts +0 -18
- package/templates/Projects/default/src/lib/i18n/navigation.ts +0 -19
- package/templates/Projects/default/src/lib/i18n/request.ts +0 -31
- package/templates/Projects/default/src/lib/i18n/routing.ts +0 -20
- package/templates/Projects/default/src/lib/utils.ts +0 -6
- package/templates/Projects/default/src/ui/Dashboard/LogoutButton.tsx +0 -27
- package/templates/Projects/default/src/ui/Dashboard/StatsCard.tsx +0 -14
- package/templates/Projects/default/src/ui/Dashboard/WelcomeCard.tsx +0 -10
- package/templates/Projects/default/src/ui/Dashboard/page-ui.tsx +0 -23
- package/templates/Projects/default/src/ui/Login/page-ui.tsx +0 -22
- package/templates/Projects/default/src/ui/Register/page-ui.tsx +0 -26
- package/templates/Projects/default/src/ui/Settings/page-ui.tsx +0 -17
- package/templates/Projects/default/src/ui/UserInfo/page-ui.tsx +0 -17
- package/templates/Projects/default/src/ui/_global/BackButton.tsx +0 -17
- package/templates/Projects/default/src/ui/_global/Button.tsx +0 -75
- package/templates/Projects/default/src/ui/_global/GlobalHeader.tsx +0 -55
- package/templates/Projects/default/src/ui/_global/GlobalMain.tsx +0 -15
- package/templates/Projects/default/src/ui/_global/Loading.tsx +0 -13
- package/templates/Projects/default/src/ui/_global/LocaleSwitcher.tsx +0 -38
- package/templates/Projects/default/src/ui/_global/PublicNav.tsx +0 -91
- package/templates/Projects/default/src/ui/_global/ThemeToggle.tsx +0 -53
- package/templates/Projects/default/src/ui/_global/UserNav.tsx +0 -35
- package/templates/Projects/default/src/ui/_home/page-ui.tsx +0 -27
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|

|
|
14
14
|

|
|
15
15
|

|
|
16
|
+

|
|
16
17
|
|
|
17
18
|

|
|
18
19
|

|
package/bin.ts
CHANGED
|
File without changes
|
package/install.sh
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-next-pro-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Advanced Next.js project scaffolder with i18n, Tailwind, App Router and more.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/Rising-Corporation/create-next-pro-cli.git"
|
|
8
8
|
},
|
|
9
9
|
"bin": {
|
|
10
|
-
"create-next-pro": "./bin.
|
|
10
|
+
"create-next-pro": "./dist/bin.js"
|
|
11
11
|
},
|
|
12
12
|
"author": "MrRise",
|
|
13
13
|
"license": "MIT",
|
|
@@ -17,12 +17,14 @@
|
|
|
17
17
|
"scaffold-dev": "bun run src/scaffold-dev.ts",
|
|
18
18
|
"postinstall": "bash install.sh",
|
|
19
19
|
"test": "bun test",
|
|
20
|
+
"clean": "rm -rf dist",
|
|
20
21
|
"build": "bun build bin.ts --outdir dist --target bun",
|
|
21
|
-
"prepublishOnly": "bun run build",
|
|
22
|
+
"prepublishOnly": "bun run clean && bun run build",
|
|
22
23
|
"commit": "cz",
|
|
23
24
|
"release": "bunx --bun standard-version",
|
|
24
25
|
"prepare-husky": "husky",
|
|
25
|
-
"version-patch": "npm version patch"
|
|
26
|
+
"version-patch": "npm version patch",
|
|
27
|
+
"git-fullpush": "git add -A && bun commit && bun version-patch && git push origin master"
|
|
26
28
|
},
|
|
27
29
|
"config": {
|
|
28
30
|
"commitizen": {
|
package/src/index.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
|
|
3
|
-
import { addComponent } from "./lib/addComponent";
|
|
4
|
-
import { addPage } from "./lib/addPage";
|
|
5
|
-
import { rmPage } from "./lib/rmPage";
|
|
6
|
-
import { createProject } from "./lib/createProject";
|
|
7
|
-
import { createProjectWithPrompt } from "./lib/createProjectWithPrompt";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Main CLI entry point for create-next-pro.
|
|
11
|
-
*
|
|
12
|
-
* Note: For now, the project behaves as if --force is always enabled and no creation prompt is taken into account.
|
|
13
|
-
* All actions are performed directly without confirmation.
|
|
14
|
-
*/
|
|
15
|
-
export async function main() {
|
|
16
|
-
console.log("🚀 Welcome to create-next-pro\n");
|
|
17
|
-
|
|
18
|
-
let args = Bun.argv.slice(2);
|
|
19
|
-
const force = args.includes("--force");
|
|
20
|
-
// For now, --force is always considered enabled but do not overwrite existing projects
|
|
21
|
-
// WARNING: if you enable --force it will overwrite existing projects. This is a temporary setting for development purposes.
|
|
22
|
-
// const force = true;
|
|
23
|
-
|
|
24
|
-
// If addpage is called without options, add default flags -LPl
|
|
25
|
-
if (args[0] === "addpage" && args.length === 1) {
|
|
26
|
-
args.push("-LPl");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Handle addcomponent command: create a component in the correct location and update translation JSON.
|
|
31
|
-
*/
|
|
32
|
-
if (args[0] === "addcomponent") {
|
|
33
|
-
addComponent(args);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Handle addpage command: create a page (nested or not) and update translation JSON.
|
|
39
|
-
*/
|
|
40
|
-
if (args[0] === "addpage") {
|
|
41
|
-
addPage(args);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Handle rmpage command: remove a page and all related files/folders.
|
|
47
|
-
*/
|
|
48
|
-
if (args[0] === "rmpage") {
|
|
49
|
-
rmPage(args);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Handle direct project creation if a name argument is provided.
|
|
55
|
-
*/
|
|
56
|
-
const nameArg = args.find((arg) => !arg.startsWith("--"));
|
|
57
|
-
|
|
58
|
-
if (nameArg) {
|
|
59
|
-
createProject(nameArg, force);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Interactive prompt for project creation (not currently used, see note above).
|
|
65
|
-
*/
|
|
66
|
-
await createProjectWithPrompt();
|
|
67
|
-
}
|
package/src/lib/addComponent.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
import { mkdir, readFile, writeFile, readdir } from "node:fs/promises";
|
|
3
|
-
import prompts from "prompts";
|
|
4
|
-
|
|
5
|
-
import { capitalize, loadConfig } from "./utils";
|
|
6
|
-
|
|
7
|
-
import { existsSync, statSync } from "node:fs";
|
|
8
|
-
|
|
9
|
-
export async function addComponent(args: string[]) {
|
|
10
|
-
let componentName = args[1];
|
|
11
|
-
let pageScope = null;
|
|
12
|
-
let pageIndex = args.findIndex((arg) => arg === "-P" || arg === "--page");
|
|
13
|
-
if (pageIndex !== -1 && args[pageIndex + 1]) {
|
|
14
|
-
pageScope = args[pageIndex + 1];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Handle nested pageScope (e.g. ParentPage.ChildPage)
|
|
18
|
-
let nestedPath = null;
|
|
19
|
-
if (pageScope && pageScope.includes(".")) {
|
|
20
|
-
nestedPath = join(...pageScope.split("."));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (!componentName || componentName.startsWith("-")) {
|
|
24
|
-
// Si le nom n'est pas fourni ou est une option, demander via prompt
|
|
25
|
-
const response = await prompts.prompt({
|
|
26
|
-
type: "text",
|
|
27
|
-
name: "componentName",
|
|
28
|
-
message: "🧩 Component name to add:",
|
|
29
|
-
validate: (name: string) => (name ? true : "Component name is required"),
|
|
30
|
-
});
|
|
31
|
-
componentName = response.componentName;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const config = await loadConfig();
|
|
35
|
-
if (!config) {
|
|
36
|
-
console.error(
|
|
37
|
-
"❌ Configuration file cnp.config.json not found. Run this command from the project root."
|
|
38
|
-
);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const useI18n = !!config.useI18n;
|
|
42
|
-
|
|
43
|
-
const componentNameUpper = capitalize(componentName);
|
|
44
|
-
const templatePath = join(
|
|
45
|
-
import.meta.dir,
|
|
46
|
-
"..",
|
|
47
|
-
"..",
|
|
48
|
-
"templates",
|
|
49
|
-
"Component"
|
|
50
|
-
);
|
|
51
|
-
let messagesPath: string | null = null;
|
|
52
|
-
if (useI18n) {
|
|
53
|
-
messagesPath = join(process.cwd(), "messages");
|
|
54
|
-
if (!existsSync(messagesPath)) {
|
|
55
|
-
console.error("❌ Messages directory missing. Ensure i18n was configured.");
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Determine target path for the component
|
|
61
|
-
let componentTargetPath;
|
|
62
|
-
let translationKey;
|
|
63
|
-
if (pageScope) {
|
|
64
|
-
if (nestedPath) {
|
|
65
|
-
componentTargetPath = join(process.cwd(), "src", "ui", nestedPath);
|
|
66
|
-
translationKey = pageScope;
|
|
67
|
-
} else {
|
|
68
|
-
componentTargetPath = join(process.cwd(), "src", "ui", pageScope);
|
|
69
|
-
translationKey = pageScope;
|
|
70
|
-
}
|
|
71
|
-
} else {
|
|
72
|
-
componentTargetPath = join(process.cwd(), "src", "ui", "_global");
|
|
73
|
-
translationKey = "_global_ui";
|
|
74
|
-
}
|
|
75
|
-
if (!existsSync(componentTargetPath)) {
|
|
76
|
-
await mkdir(componentTargetPath, { recursive: true });
|
|
77
|
-
}
|
|
78
|
-
const componentFile = join(componentTargetPath, `${componentNameUpper}.tsx`);
|
|
79
|
-
|
|
80
|
-
// Read and adapt the TSX template
|
|
81
|
-
const templateComponentPath = join(templatePath, "Component.tsx");
|
|
82
|
-
if (existsSync(templateComponentPath)) {
|
|
83
|
-
let content = await readFile(templateComponentPath, "utf-8");
|
|
84
|
-
// Remplacement du nom du component et de la clé de traduction
|
|
85
|
-
content = content
|
|
86
|
-
.replace(/Component/g, componentNameUpper)
|
|
87
|
-
.replace(/componentPage/g, translationKey);
|
|
88
|
-
await writeFile(componentFile, content);
|
|
89
|
-
console.log(`📄 File created: ${componentFile}`);
|
|
90
|
-
} else {
|
|
91
|
-
console.error(
|
|
92
|
-
"❌ Template Component.tsx introuvable :",
|
|
93
|
-
templateComponentPath
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (useI18n && messagesPath) {
|
|
99
|
-
const entries = await readdir(messagesPath, { withFileTypes: true });
|
|
100
|
-
const langDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
101
|
-
const jsonTemplate = join(templatePath, "component.json");
|
|
102
|
-
if (!existsSync(jsonTemplate)) {
|
|
103
|
-
console.error("❌ Template component.json not found:", jsonTemplate);
|
|
104
|
-
return;
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
const jsonContent = await readFile(jsonTemplate, "utf-8");
|
|
108
|
-
const parsed = JSON.parse(jsonContent);
|
|
109
|
-
|
|
110
|
-
for (const locale of langDirs) {
|
|
111
|
-
// Only process if messages/<locale> is a directory
|
|
112
|
-
const localeDir = join(messagesPath, locale);
|
|
113
|
-
if (!existsSync(localeDir) || !statSync(localeDir).isDirectory())
|
|
114
|
-
continue;
|
|
115
|
-
let jsonTarget;
|
|
116
|
-
if (pageScope) {
|
|
117
|
-
jsonTarget = join(messagesPath, locale, `${pageScope}.json`);
|
|
118
|
-
} else {
|
|
119
|
-
jsonTarget = join(messagesPath, locale, `_global_ui.json`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
let current: Record<string, any> = {};
|
|
123
|
-
if (existsSync(jsonTarget)) {
|
|
124
|
-
const jsonFile = await readFile(jsonTarget, "utf-8");
|
|
125
|
-
current = JSON.parse(jsonFile) as Record<string, any>;
|
|
126
|
-
}
|
|
127
|
-
current[componentNameUpper] = parsed;
|
|
128
|
-
await writeFile(jsonTarget, JSON.stringify(current, null, 2));
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
console.log("ℹ️ Skipping translation entries; next-intl not enabled.");
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
console.log(
|
|
135
|
-
`✅ Component "${componentNameUpper}" added ${
|
|
136
|
-
pageScope ? `to page ${pageScope}` : "globally"
|
|
137
|
-
}${useI18n ? " with localized messages" : ""}.`
|
|
138
|
-
);
|
|
139
|
-
}
|
package/src/lib/addPage.ts
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
import { mkdir, readFile, writeFile, readdir } from "node:fs/promises";
|
|
3
|
-
import prompts from "prompts";
|
|
4
|
-
|
|
5
|
-
import { capitalize, toFileName, loadConfig } from "./utils";
|
|
6
|
-
|
|
7
|
-
import { existsSync, statSync } from "node:fs";
|
|
8
|
-
|
|
9
|
-
export async function addPage(args: string[]) {
|
|
10
|
-
let pageName = args[1];
|
|
11
|
-
if (!pageName || pageName.startsWith("-")) {
|
|
12
|
-
const response = await prompts.prompt({
|
|
13
|
-
type: "text",
|
|
14
|
-
name: "pageName",
|
|
15
|
-
message: "📝 Page name to add:",
|
|
16
|
-
validate: (name: string) => (name ? true : "Page name is required"),
|
|
17
|
-
});
|
|
18
|
-
pageName = response.pageName;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Handle nested pages
|
|
22
|
-
let parentName = null;
|
|
23
|
-
let childName = null;
|
|
24
|
-
if (pageName.includes(".")) {
|
|
25
|
-
[parentName, childName] = pageName.split(".");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let shortFlags = args.find((arg) => /^-[A-Za-z]+$/.test(arg));
|
|
29
|
-
let longFlags = new Set(args.filter((a) => a.startsWith("--")));
|
|
30
|
-
const flags = new Set<string>();
|
|
31
|
-
|
|
32
|
-
if (!shortFlags && Array.from(longFlags).length === 0) {
|
|
33
|
-
shortFlags = "-LPl";
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (shortFlags) {
|
|
37
|
-
for (const char of shortFlags.slice(1)) {
|
|
38
|
-
switch (char) {
|
|
39
|
-
case "L":
|
|
40
|
-
flags.add("layout");
|
|
41
|
-
break;
|
|
42
|
-
case "P":
|
|
43
|
-
flags.add("page");
|
|
44
|
-
break;
|
|
45
|
-
case "l":
|
|
46
|
-
flags.add("loading");
|
|
47
|
-
break;
|
|
48
|
-
case "n":
|
|
49
|
-
flags.add("not-found");
|
|
50
|
-
break;
|
|
51
|
-
case "e":
|
|
52
|
-
flags.add("error");
|
|
53
|
-
break;
|
|
54
|
-
case "g":
|
|
55
|
-
flags.add("global-error");
|
|
56
|
-
break;
|
|
57
|
-
case "r":
|
|
58
|
-
flags.add("route");
|
|
59
|
-
break;
|
|
60
|
-
case "t":
|
|
61
|
-
flags.add("template");
|
|
62
|
-
break;
|
|
63
|
-
case "d":
|
|
64
|
-
flags.add("default");
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
for (const flag of [
|
|
71
|
-
"layout",
|
|
72
|
-
"page",
|
|
73
|
-
"loading",
|
|
74
|
-
"not-found",
|
|
75
|
-
"error",
|
|
76
|
-
"global-error",
|
|
77
|
-
"route",
|
|
78
|
-
"template",
|
|
79
|
-
"default",
|
|
80
|
-
]) {
|
|
81
|
-
if (longFlags.has("--" + flag)) flags.add(flag);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const config = await loadConfig();
|
|
85
|
-
if (!config) {
|
|
86
|
-
console.error("❌ Configuration file cnp.config.json not found. Run this command from the project root.");
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const useI18n = !!config.useI18n;
|
|
90
|
-
|
|
91
|
-
const srcSegments = ["src", "app"];
|
|
92
|
-
if (useI18n) srcSegments.push("[locale]");
|
|
93
|
-
const srcPath = join(process.cwd(), ...srcSegments);
|
|
94
|
-
if (!existsSync(srcPath)) {
|
|
95
|
-
console.error(`❌ Expected directory not found: ${srcPath}`);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
let messagesPath: string | null = null;
|
|
100
|
-
let locales: string[] = [];
|
|
101
|
-
if (useI18n) {
|
|
102
|
-
messagesPath = join(process.cwd(), "messages");
|
|
103
|
-
if (!existsSync(messagesPath)) {
|
|
104
|
-
console.error("❌ Messages directory missing. Ensure i18n was configured.");
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
const entries = await readdir(messagesPath, { withFileTypes: true });
|
|
108
|
-
locales = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const templatePath = join(import.meta.dir, "..", "..", "templates", "Page");
|
|
112
|
-
|
|
113
|
-
// Create folders/files for nested or simple page
|
|
114
|
-
let uiPageDir, localePagePath, jsonFileName;
|
|
115
|
-
if (parentName && childName) {
|
|
116
|
-
uiPageDir = join(process.cwd(), "src", "ui", parentName, childName);
|
|
117
|
-
localePagePath = join(srcPath, parentName, childName);
|
|
118
|
-
jsonFileName = parentName;
|
|
119
|
-
} else {
|
|
120
|
-
uiPageDir = join(process.cwd(), "src", "ui", pageName);
|
|
121
|
-
localePagePath = join(srcPath, pageName);
|
|
122
|
-
jsonFileName = pageName;
|
|
123
|
-
}
|
|
124
|
-
if (!existsSync(uiPageDir)) {
|
|
125
|
-
await mkdir(uiPageDir, { recursive: true });
|
|
126
|
-
}
|
|
127
|
-
const uiPageFile = join(uiPageDir, "page-ui.tsx");
|
|
128
|
-
const uiPageTemplate = join(templatePath, "page-ui.tsx");
|
|
129
|
-
if (existsSync(uiPageTemplate)) {
|
|
130
|
-
let uiContent = await readFile(uiPageTemplate, "utf-8");
|
|
131
|
-
uiContent = uiContent
|
|
132
|
-
.replace(/template/g, childName || pageName)
|
|
133
|
-
.replace(/Template/g, capitalize(childName || pageName));
|
|
134
|
-
await writeFile(uiPageFile, uiContent);
|
|
135
|
-
console.log(`📄 File created: ${uiPageFile}`);
|
|
136
|
-
} else {
|
|
137
|
-
console.warn("⚠️ Template page-ui.tsx manquant.");
|
|
138
|
-
}
|
|
139
|
-
if (!existsSync(localePagePath)) {
|
|
140
|
-
await mkdir(localePagePath, { recursive: true });
|
|
141
|
-
}
|
|
142
|
-
for (const flag of flags) {
|
|
143
|
-
const filename = toFileName(flag);
|
|
144
|
-
const src = join(templatePath, filename);
|
|
145
|
-
const dst = join(localePagePath, filename);
|
|
146
|
-
if (!existsSync(src)) {
|
|
147
|
-
console.warn(`⚠️ Missing template file: ${filename}`);
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
const content = await readFile(src, "utf-8");
|
|
151
|
-
const replaced = content
|
|
152
|
-
.replace(/template/g, childName || pageName)
|
|
153
|
-
.replace(/Template/g, capitalize(childName || pageName));
|
|
154
|
-
await writeFile(dst, replaced);
|
|
155
|
-
console.log(`📄 File created: ${dst}`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (useI18n && messagesPath) {
|
|
159
|
-
const jsonTemplate = join(templatePath, "page.json");
|
|
160
|
-
if (!existsSync(jsonTemplate)) {
|
|
161
|
-
console.warn("⚠️ Missing template page.json.");
|
|
162
|
-
|
|
163
|
-
} else {
|
|
164
|
-
const content = await readFile(jsonTemplate, "utf-8");
|
|
165
|
-
const replaced = content
|
|
166
|
-
.replace(/template/g, childName || pageName)
|
|
167
|
-
.replace(/Template/g, capitalize(childName || pageName));
|
|
168
|
-
for (const locale of locales) {
|
|
169
|
-
// Only process if messages/<locale> is a directory
|
|
170
|
-
const localeDir = join(messagesPath, locale);
|
|
171
|
-
if (!existsSync(localeDir) || !statSync(localeDir).isDirectory())
|
|
172
|
-
continue;
|
|
173
|
-
const jsonTarget = join(messagesPath, locale, `${jsonFileName}.json`);
|
|
174
|
-
let current: Record<string, any> = {};
|
|
175
|
-
if (existsSync(jsonTarget)) {
|
|
176
|
-
const jsonFile = await readFile(jsonTarget, "utf-8");
|
|
177
|
-
try {
|
|
178
|
-
current = JSON.parse(jsonFile) as Record<string, any>;
|
|
179
|
-
} catch {
|
|
180
|
-
current = {};
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
if (parentName && childName) {
|
|
184
|
-
current[childName] = JSON.parse(replaced);
|
|
185
|
-
} else {
|
|
186
|
-
// fichier simple
|
|
187
|
-
current = JSON.parse(replaced);
|
|
188
|
-
}
|
|
189
|
-
await writeFile(jsonTarget, JSON.stringify(current, null, 2));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
} else {
|
|
193
|
-
console.log("ℹ️ Skipping translation templates; next-intl not enabled.");
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
console.log(
|
|
197
|
-
`✅ Page "${pageName}" with templates added${
|
|
198
|
-
useI18n ? " for each locale" : ""
|
|
199
|
-
}.`
|
|
200
|
-
);
|
|
201
|
-
}
|
package/src/lib/createProject.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { scaffoldProject } from "../scaffold";
|
|
2
|
-
export async function createProject(nameArg: string, force: boolean) {
|
|
3
|
-
const response = {
|
|
4
|
-
projectName: nameArg,
|
|
5
|
-
useTypescript: true,
|
|
6
|
-
useEslint: true,
|
|
7
|
-
useTailwind: true,
|
|
8
|
-
useSrcDir: true,
|
|
9
|
-
useTurbopack: true,
|
|
10
|
-
useI18n: true,
|
|
11
|
-
customAlias: false,
|
|
12
|
-
importAlias: "@/*",
|
|
13
|
-
force,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
console.log(`📦 Creating project "${response.projectName}"...`);
|
|
17
|
-
await scaffoldProject(response);
|
|
18
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { scaffoldProject } from "../scaffold";
|
|
2
|
-
import prompts from "prompts";
|
|
3
|
-
export async function createProjectWithPrompt() {
|
|
4
|
-
const response = await prompts.prompt([
|
|
5
|
-
{
|
|
6
|
-
type: "text",
|
|
7
|
-
name: "projectName",
|
|
8
|
-
message: "🧱 Project name:",
|
|
9
|
-
initial: "my-next-app",
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
type: "toggle",
|
|
13
|
-
name: "useTypescript",
|
|
14
|
-
message: "✔ Use TypeScript?",
|
|
15
|
-
initial: true,
|
|
16
|
-
active: "Yes",
|
|
17
|
-
inactive: "No",
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
type: "toggle",
|
|
21
|
-
name: "useEslint",
|
|
22
|
-
message: "✔ Use ESLint?",
|
|
23
|
-
initial: true,
|
|
24
|
-
active: "Yes",
|
|
25
|
-
inactive: "No",
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
type: "toggle",
|
|
29
|
-
name: "useTailwind",
|
|
30
|
-
message: "✔ Use Tailwind CSS?",
|
|
31
|
-
initial: true,
|
|
32
|
-
active: "Yes",
|
|
33
|
-
inactive: "No",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
type: "toggle",
|
|
37
|
-
name: "useSrcDir",
|
|
38
|
-
message: "✔ Use `src/` directory?",
|
|
39
|
-
initial: false,
|
|
40
|
-
active: "Yes",
|
|
41
|
-
inactive: "No",
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
type: "toggle",
|
|
45
|
-
name: "useTurbopack",
|
|
46
|
-
message: "✔ Use Turbopack for `next dev`?",
|
|
47
|
-
initial: true,
|
|
48
|
-
active: "Yes",
|
|
49
|
-
inactive: "No",
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
type: "toggle",
|
|
53
|
-
name: "useI18n",
|
|
54
|
-
message: "✔ Use i18n with next-intl for translations?",
|
|
55
|
-
initial: true,
|
|
56
|
-
active: "Yes",
|
|
57
|
-
inactive: "No",
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
type: "toggle",
|
|
61
|
-
name: "customAlias",
|
|
62
|
-
message: "✔ Customize import alias (`@/*` by default)?",
|
|
63
|
-
initial: false,
|
|
64
|
-
active: "Yes",
|
|
65
|
-
inactive: "No",
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
type: (prev: boolean) => (prev ? "text" : null),
|
|
69
|
-
name: "importAlias",
|
|
70
|
-
message: "✔ What import alias would you like?",
|
|
71
|
-
initial: "@core/*",
|
|
72
|
-
},
|
|
73
|
-
]);
|
|
74
|
-
|
|
75
|
-
console.log("\n✅ Your choices:");
|
|
76
|
-
console.log(response);
|
|
77
|
-
|
|
78
|
-
await scaffoldProject(response);
|
|
79
|
-
}
|
package/src/lib/rmPage.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
import { writeFile, readdir } from "node:fs/promises";
|
|
3
|
-
import prompts from "prompts";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
|
-
|
|
6
|
-
export async function rmPage(args: string[]) {
|
|
7
|
-
let pageName = args[1];
|
|
8
|
-
if (!pageName || pageName.startsWith("-")) {
|
|
9
|
-
const response = await prompts.prompt({
|
|
10
|
-
type: "text",
|
|
11
|
-
name: "pageName",
|
|
12
|
-
message: "🗑️ Page name to remove:",
|
|
13
|
-
validate: (name: string) => (name ? true : "Page name is required"),
|
|
14
|
-
});
|
|
15
|
-
pageName = response.pageName;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Remove translation files messages/<lang>/<PageName>.json
|
|
19
|
-
const messagesPath = join(process.cwd(), "messages");
|
|
20
|
-
const entries = await readdir(messagesPath, { withFileTypes: true });
|
|
21
|
-
const langDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
22
|
-
for (const locale of langDirs) {
|
|
23
|
-
const jsonTarget = join(messagesPath, locale, `${pageName}.json`);
|
|
24
|
-
if (existsSync(jsonTarget)) {
|
|
25
|
-
await writeFile(jsonTarget, "");
|
|
26
|
-
await import("node:child_process").then((cp) =>
|
|
27
|
-
cp.execSync(`rm -f '${jsonTarget}'`)
|
|
28
|
-
);
|
|
29
|
-
console.log(`🗑️ Deleted: ${jsonTarget}`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Remove folder src/ui/<PageName>
|
|
34
|
-
const uiPageDir = join(process.cwd(), "src", "ui", pageName);
|
|
35
|
-
if (existsSync(uiPageDir)) {
|
|
36
|
-
await import("node:child_process").then((cp) =>
|
|
37
|
-
cp.execSync(`rm -rf '${uiPageDir}'`)
|
|
38
|
-
);
|
|
39
|
-
console.log(`🗑️ Deleted: ${uiPageDir}`);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Remove folder src/app/[locale]/<PageName>
|
|
43
|
-
const appLocaleDir = join(process.cwd(), "src", "app", "[locale]", pageName);
|
|
44
|
-
if (existsSync(appLocaleDir)) {
|
|
45
|
-
await import("node:child_process").then((cp) =>
|
|
46
|
-
cp.execSync(`rm -rf '${appLocaleDir}'`)
|
|
47
|
-
);
|
|
48
|
-
console.log(`🗑️ Deleted: ${appLocaleDir}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
console.log(`✅ Page "${pageName}" deleted.`);
|
|
52
|
-
}
|
package/src/lib/utils.test.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import { toFileName } from "./utils";
|
|
3
|
-
|
|
4
|
-
describe("toFileName", () => {
|
|
5
|
-
const cases: [string, string][] = [
|
|
6
|
-
["layout", "layout.tsx"],
|
|
7
|
-
["page", "page.tsx"],
|
|
8
|
-
["loading", "loading.tsx"],
|
|
9
|
-
["not-found", "not-found.tsx"],
|
|
10
|
-
["error", "error.tsx"],
|
|
11
|
-
["global-error", "global-error.tsx"],
|
|
12
|
-
["route", "route.ts"],
|
|
13
|
-
["template", "template.tsx"],
|
|
14
|
-
["default", "default.tsx"],
|
|
15
|
-
["foo", "foo.tsx"],
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
for (const [key, expected] of cases) {
|
|
19
|
-
test(`maps "${key}" to "${expected}"`, () => {
|
|
20
|
-
expect(toFileName(key)).toBe(expected);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
});
|
package/src/lib/utils.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Capitalize the first letter of a string.
|
|
7
|
-
*/
|
|
8
|
-
export function capitalize(str: string): string {
|
|
9
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface CNPConfig {
|
|
13
|
-
useI18n?: boolean;
|
|
14
|
-
[key: string]: any;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Load CLI configuration from the project root.
|
|
19
|
-
* Returns null if the configuration file is missing or invalid.
|
|
20
|
-
*/
|
|
21
|
-
export async function loadConfig(): Promise<CNPConfig | null> {
|
|
22
|
-
const configPath = join(process.cwd(), "cnp.config.json");
|
|
23
|
-
if (!existsSync(configPath)) return null;
|
|
24
|
-
try {
|
|
25
|
-
const raw = await readFile(configPath, "utf-8");
|
|
26
|
-
return JSON.parse(raw) as CNPConfig;
|
|
27
|
-
} catch {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Map a key to its corresponding file name for page/component templates.
|
|
34
|
-
* @param key string
|
|
35
|
-
* @returns file name string
|
|
36
|
-
*/
|
|
37
|
-
export function toFileName(key: string): string {
|
|
38
|
-
switch (key) {
|
|
39
|
-
case "layout":
|
|
40
|
-
return "layout.tsx";
|
|
41
|
-
case "page":
|
|
42
|
-
return "page.tsx";
|
|
43
|
-
case "loading":
|
|
44
|
-
return "loading.tsx";
|
|
45
|
-
case "not-found":
|
|
46
|
-
return "not-found.tsx";
|
|
47
|
-
case "error":
|
|
48
|
-
return "error.tsx";
|
|
49
|
-
case "global-error":
|
|
50
|
-
return "global-error.tsx";
|
|
51
|
-
case "route":
|
|
52
|
-
return "route.ts";
|
|
53
|
-
case "template":
|
|
54
|
-
return "template.tsx";
|
|
55
|
-
case "default":
|
|
56
|
-
return "default.tsx";
|
|
57
|
-
default:
|
|
58
|
-
return `${key}.tsx`;
|
|
59
|
-
}
|
|
60
|
-
}
|