create-next-pro-cli 0.1.12 → 0.1.13
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/.github/workflows/ci.yml +38 -0
- package/README.md +104 -86
- package/dist/bin.js +5466 -0
- package/install.sh +63 -8
- package/package.json +6 -2
- package/src/lib/addComponent.ts +53 -33
- package/src/lib/addPage.ts +70 -39
- package/src/lib/utils.test.ts +23 -0
- package/src/lib/utils.ts +24 -0
- package/src/scaffold.ts +20 -4
- package/.husky/commit-msg +0 -2
- package/.husky/pre-commit +0 -2
- package/CODE_OF_CONDUCT.md +0 -33
- package/CONTRIBUTING.md +0 -44
- package/FONCTIONALITY.md +0 -25
- package/templates/Projects/default/README.md +0 -36
package/install.sh
CHANGED
|
@@ -1,18 +1,73 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# Installation script for create-next-pro
|
|
3
|
+
|
|
4
|
+
# Detect runtimes
|
|
5
|
+
bun_path=$(command -v bun)
|
|
6
|
+
deno_path=$(command -v deno)
|
|
7
|
+
node_path=$(command -v node)
|
|
8
|
+
|
|
9
|
+
if [ -n "$bun_path" ]; then
|
|
10
|
+
echo "Bun detected at $bun_path. Using Bun shebang."
|
|
11
|
+
sed -i '1s|.*|#!/usr/bin/env bun|' dist/bin.js
|
|
12
|
+
elif [ -n "$deno_path" ]; then
|
|
13
|
+
echo "Deno detected at $deno_path. Using Deno shebang."
|
|
14
|
+
sed -i '1s|.*|#!/usr/bin/env deno|' dist/bin.js
|
|
15
|
+
elif [ -n "$node_path" ]; then
|
|
16
|
+
echo "Node.js detected at $node_path. Using Node shebang."
|
|
17
|
+
sed -i '1s|.*|#!/usr/bin/env node|' dist/bin.js
|
|
18
|
+
else
|
|
19
|
+
echo "No compatible runtime (Bun, Deno, Node.js) found."
|
|
20
|
+
read -p "Do you want to install Bun? [Y/n] " yn
|
|
21
|
+
case $yn in
|
|
22
|
+
[Nn]*)
|
|
23
|
+
echo "Installation cancelled. Do you want to delete the parent folder? [Y/n] "
|
|
24
|
+
read delyn
|
|
25
|
+
case $delyn in
|
|
26
|
+
[Nn]*) echo "Folder kept."; exit 1;;
|
|
27
|
+
*)
|
|
28
|
+
parent_dir="$(dirname $(pwd))"
|
|
29
|
+
echo "Deleting folder $parent_dir..."
|
|
30
|
+
rm -rf "$parent_dir"
|
|
31
|
+
echo "Folder deleted."
|
|
32
|
+
exit 1
|
|
33
|
+
;;
|
|
34
|
+
esac
|
|
35
|
+
;;
|
|
36
|
+
*)
|
|
37
|
+
echo "Please install Bun, node or Deno!"
|
|
38
|
+
echo "Installation instructions:"
|
|
39
|
+
echo "Bun: https://bun.com/"
|
|
40
|
+
echo "Node.js: https://nodejs.org/"
|
|
41
|
+
echo "Deno: https://deno.land/"
|
|
42
|
+
exit 1
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
fi
|
|
3
46
|
|
|
4
47
|
COMPLETION_SCRIPT="$(pwd)/create-next-pro-completion.sh"
|
|
5
|
-
BASHRC="$HOME/.bashrc"
|
|
6
48
|
|
|
7
|
-
|
|
49
|
+
# Choose shell for autocompletion
|
|
50
|
+
read -p "Which shell do you use? [1] zsh, [2] bash (default: bash): " shell_choice
|
|
51
|
+
case $shell_choice in
|
|
52
|
+
1|zsh|Zsh)
|
|
53
|
+
RC_FILE="$HOME/.zshrc"
|
|
54
|
+
SHELL_NAME="zsh"
|
|
55
|
+
;;
|
|
56
|
+
*)
|
|
57
|
+
RC_FILE="$HOME/.bashrc"
|
|
58
|
+
SHELL_NAME="bash"
|
|
59
|
+
;;
|
|
60
|
+
esac
|
|
61
|
+
|
|
62
|
+
read -p "Do you want to add create-next-pro autocompletion to your $SHELL_NAME rc file? [Y/n] " yn
|
|
8
63
|
case $yn in
|
|
9
|
-
[Nn]*) echo "ℹ️
|
|
64
|
+
[Nn]*) echo "ℹ️ Autocompletion not added"; exit;;
|
|
10
65
|
*)
|
|
11
|
-
if ! grep -q "$COMPLETION_SCRIPT" "$
|
|
12
|
-
echo "source $COMPLETION_SCRIPT" >> "$
|
|
13
|
-
echo "✅
|
|
66
|
+
if ! grep -q "$COMPLETION_SCRIPT" "$RC_FILE"; then
|
|
67
|
+
echo "source $COMPLETION_SCRIPT" >> "$RC_FILE"
|
|
68
|
+
echo "✅ Autocompletion script added to $RC_FILE"
|
|
14
69
|
else
|
|
15
|
-
echo "ℹ️ Script
|
|
70
|
+
echo "ℹ️ Script already present in $RC_FILE"
|
|
16
71
|
fi
|
|
17
72
|
;;
|
|
18
73
|
esac
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-next-pro-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Advanced Next.js project scaffolder with i18n, Tailwind, App Router and more.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,9 +16,13 @@
|
|
|
16
16
|
"dev": "bun run bin.ts",
|
|
17
17
|
"scaffold-dev": "bun run src/scaffold-dev.ts",
|
|
18
18
|
"postinstall": "bash install.sh",
|
|
19
|
+
"test": "bun test",
|
|
20
|
+
"build": "bun build bin.ts --outdir dist --target bun",
|
|
21
|
+
"prepublishOnly": "bun run build",
|
|
19
22
|
"commit": "cz",
|
|
20
23
|
"release": "bunx --bun standard-version",
|
|
21
|
-
"prepare-husky": "husky"
|
|
24
|
+
"prepare-husky": "husky",
|
|
25
|
+
"version-patch": "npm version patch"
|
|
22
26
|
},
|
|
23
27
|
"config": {
|
|
24
28
|
"commitizen": {
|
package/src/lib/addComponent.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { mkdir, readFile, writeFile, readdir } from "node:fs/promises";
|
|
3
3
|
import prompts from "prompts";
|
|
4
|
-
|
|
5
|
-
import {
|
|
4
|
+
|
|
5
|
+
import { capitalize, loadConfig } from "./utils";
|
|
6
|
+
|
|
7
|
+
import { existsSync, statSync } from "node:fs";
|
|
6
8
|
|
|
7
9
|
export async function addComponent(args: string[]) {
|
|
8
10
|
let componentName = args[1];
|
|
@@ -29,6 +31,15 @@ export async function addComponent(args: string[]) {
|
|
|
29
31
|
componentName = response.componentName;
|
|
30
32
|
}
|
|
31
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
|
+
|
|
32
43
|
const componentNameUpper = capitalize(componentName);
|
|
33
44
|
const templatePath = join(
|
|
34
45
|
import.meta.dir,
|
|
@@ -37,7 +48,14 @@ export async function addComponent(args: string[]) {
|
|
|
37
48
|
"templates",
|
|
38
49
|
"Component"
|
|
39
50
|
);
|
|
40
|
-
|
|
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
|
+
}
|
|
41
59
|
|
|
42
60
|
// Determine target path for the component
|
|
43
61
|
let componentTargetPath;
|
|
@@ -76,44 +94,46 @@ export async function addComponent(args: string[]) {
|
|
|
76
94
|
);
|
|
77
95
|
}
|
|
78
96
|
|
|
79
|
-
// Add the component to each language's JSON file (only folders)
|
|
80
|
-
const entries = await readdir(messagesPath, { withFileTypes: true });
|
|
81
|
-
const langDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
82
|
-
const jsonTemplate = join(templatePath, "component.json");
|
|
83
|
-
if (!existsSync(jsonTemplate)) {
|
|
84
|
-
console.error("❌ Template component.json not found:", jsonTemplate);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const jsonContent = await readFile(jsonTemplate, "utf-8");
|
|
88
|
-
const parsed = JSON.parse(jsonContent);
|
|
89
97
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
let jsonTarget;
|
|
99
|
-
if (pageScope) {
|
|
100
|
-
jsonTarget = join(messagesPath, locale, `${pageScope}.json`);
|
|
101
|
-
} else {
|
|
102
|
-
jsonTarget = join(messagesPath, locale, `_global_ui.json`);
|
|
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
|
+
|
|
103
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
|
+
}
|
|
104
121
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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));
|
|
109
129
|
}
|
|
110
|
-
|
|
111
|
-
|
|
130
|
+
} else {
|
|
131
|
+
console.log("ℹ️ Skipping translation entries; next-intl not enabled.");
|
|
112
132
|
}
|
|
113
133
|
|
|
114
134
|
console.log(
|
|
115
135
|
`✅ Component "${componentNameUpper}" added ${
|
|
116
136
|
pageScope ? `to page ${pageScope}` : "globally"
|
|
117
|
-
} with localized messages.`
|
|
137
|
+
}${useI18n ? " with localized messages" : ""}.`
|
|
118
138
|
);
|
|
119
139
|
}
|
package/src/lib/addPage.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { mkdir, readFile, writeFile, readdir } from "node:fs/promises";
|
|
3
3
|
import prompts from "prompts";
|
|
4
|
-
|
|
5
|
-
import {
|
|
4
|
+
|
|
5
|
+
import { capitalize, toFileName, loadConfig } from "./utils";
|
|
6
|
+
|
|
7
|
+
import { existsSync, statSync } from "node:fs";
|
|
6
8
|
|
|
7
9
|
export async function addPage(args: string[]) {
|
|
8
10
|
let pageName = args[1];
|
|
@@ -79,11 +81,34 @@ export async function addPage(args: string[]) {
|
|
|
79
81
|
if (longFlags.has("--" + flag)) flags.add(flag);
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
const
|
|
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
|
+
|
|
84
111
|
const templatePath = join(import.meta.dir, "..", "..", "templates", "Page");
|
|
85
|
-
const entries = await readdir(messagesPath, { withFileTypes: true });
|
|
86
|
-
const locales = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
87
112
|
|
|
88
113
|
// Create folders/files for nested or simple page
|
|
89
114
|
let uiPageDir, localePagePath, jsonFileName;
|
|
@@ -130,41 +155,47 @@ export async function addPage(args: string[]) {
|
|
|
130
155
|
console.log(`📄 File created: ${dst}`);
|
|
131
156
|
}
|
|
132
157
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const content = await readFile(jsonTemplate, "utf-8");
|
|
139
|
-
const replaced = content
|
|
140
|
-
.replace(/template/g, childName || pageName)
|
|
141
|
-
.replace(/Template/g, capitalize(childName || pageName));
|
|
142
|
-
for (const locale of locales) {
|
|
143
|
-
// Only process if messages/<locale> is a directory
|
|
144
|
-
const localeDir = join(messagesPath, locale);
|
|
145
|
-
if (
|
|
146
|
-
!existsSync(localeDir) ||
|
|
147
|
-
!require("node:fs").statSync(localeDir).isDirectory()
|
|
148
|
-
)
|
|
149
|
-
continue;
|
|
150
|
-
const jsonTarget = join(messagesPath, locale, `${jsonFileName}.json`);
|
|
151
|
-
let current: Record<string, any> = {};
|
|
152
|
-
if (existsSync(jsonTarget)) {
|
|
153
|
-
const jsonFile = await readFile(jsonTarget, "utf-8");
|
|
154
|
-
try {
|
|
155
|
-
current = JSON.parse(jsonFile) as Record<string, any>;
|
|
156
|
-
} catch {
|
|
157
|
-
current = {};
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (parentName && childName) {
|
|
161
|
-
current[childName] = JSON.parse(replaced);
|
|
158
|
+
if (useI18n && messagesPath) {
|
|
159
|
+
const jsonTemplate = join(templatePath, "page.json");
|
|
160
|
+
if (!existsSync(jsonTemplate)) {
|
|
161
|
+
console.warn("⚠️ Missing template page.json.");
|
|
162
|
+
|
|
162
163
|
} else {
|
|
163
|
-
|
|
164
|
-
|
|
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
|
+
}
|
|
165
191
|
}
|
|
166
|
-
|
|
192
|
+
} else {
|
|
193
|
+
console.log("ℹ️ Skipping translation templates; next-intl not enabled.");
|
|
167
194
|
}
|
|
168
195
|
|
|
169
|
-
console.log(
|
|
196
|
+
console.log(
|
|
197
|
+
`✅ Page "${pageName}" with templates added${
|
|
198
|
+
useI18n ? " for each locale" : ""
|
|
199
|
+
}.`
|
|
200
|
+
);
|
|
170
201
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* Capitalize the first letter of a string.
|
|
3
7
|
*/
|
|
@@ -5,6 +9,26 @@ export function capitalize(str: string): string {
|
|
|
5
9
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
6
10
|
}
|
|
7
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
|
+
|
|
8
32
|
/**
|
|
9
33
|
* Map a key to its corresponding file name for page/component templates.
|
|
10
34
|
* @param key string
|
package/src/scaffold.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/scaffold.ts
|
|
2
2
|
|
|
3
|
-
import { cp, mkdir, rm } from "node:fs/promises";
|
|
3
|
+
import { cp, mkdir, rm, writeFile, readFile } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
|
|
@@ -36,7 +36,7 @@ export async function scaffoldProject(options: ScaffoldOptions) {
|
|
|
36
36
|
"..",
|
|
37
37
|
"templates",
|
|
38
38
|
"Projects",
|
|
39
|
-
"default"
|
|
39
|
+
"default",
|
|
40
40
|
);
|
|
41
41
|
|
|
42
42
|
// Check if target directory exists
|
|
@@ -46,7 +46,7 @@ export async function scaffoldProject(options: ScaffoldOptions) {
|
|
|
46
46
|
await rm(targetPath, { recursive: true, force: true });
|
|
47
47
|
} else {
|
|
48
48
|
console.error(
|
|
49
|
-
"❌ Target directory already exists. Use --force to overwrite."
|
|
49
|
+
"❌ Target directory already exists. Use --force to overwrite.",
|
|
50
50
|
);
|
|
51
51
|
process.exit(1);
|
|
52
52
|
}
|
|
@@ -59,7 +59,23 @@ export async function scaffoldProject(options: ScaffoldOptions) {
|
|
|
59
59
|
console.log("📦 Copying files from template...");
|
|
60
60
|
await cp(templatePath, targetPath, { recursive: true });
|
|
61
61
|
|
|
62
|
-
//
|
|
62
|
+
// Apply configuration: add dependencies or files based on prompt choices
|
|
63
|
+
const pkgPath = join(targetPath, "package.json");
|
|
64
|
+
if (existsSync(pkgPath)) {
|
|
65
|
+
const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
|
|
66
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
67
|
+
if (options.useI18n) {
|
|
68
|
+
pkg.dependencies["next-intl"] =
|
|
69
|
+
pkg.dependencies["next-intl"] || "^4.3.5";
|
|
70
|
+
}
|
|
71
|
+
await writeFile(pkgPath, JSON.stringify(pkg, null, 2));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Write CLI configuration to project root
|
|
75
|
+
await writeFile(
|
|
76
|
+
join(targetPath, "cnp.config.json"),
|
|
77
|
+
JSON.stringify(options, null, 2),
|
|
78
|
+
);
|
|
63
79
|
|
|
64
80
|
console.log("✅ Project scaffolded successfully!");
|
|
65
81
|
console.log(`➡️ cd ${options.projectName} && bun install && bun dev`);
|
package/.husky/commit-msg
DELETED
package/.husky/pre-commit
DELETED
package/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
|
2
|
-
|
|
3
|
-
## Our Pledge
|
|
4
|
-
|
|
5
|
-
We as members, contributors, and leaders pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
6
|
-
|
|
7
|
-
## Our Standards
|
|
8
|
-
|
|
9
|
-
Examples of behavior that contributes to a positive environment for our community include:
|
|
10
|
-
|
|
11
|
-
- Using welcoming and inclusive language
|
|
12
|
-
- Being respectful of differing viewpoints and experiences
|
|
13
|
-
- Gracefully accepting constructive criticism
|
|
14
|
-
- Focusing on what is best for the community
|
|
15
|
-
- Showing empathy towards other community members
|
|
16
|
-
|
|
17
|
-
Examples of unacceptable behavior include:
|
|
18
|
-
|
|
19
|
-
- The use of sexualized language or imagery and unwelcome sexual attention or advances
|
|
20
|
-
- Trolling, insulting/derogatory comments, and personal or political attacks
|
|
21
|
-
- Public or private harassment
|
|
22
|
-
- Publishing others' private information, such as a physical or electronic address, without explicit permission
|
|
23
|
-
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
24
|
-
|
|
25
|
-
## Enforcement
|
|
26
|
-
|
|
27
|
-
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
|
28
|
-
|
|
29
|
-
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
|
30
|
-
|
|
31
|
-
## Attribution
|
|
32
|
-
|
|
33
|
-
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# Contributing to create-next-pro-cli
|
|
2
|
-
|
|
3
|
-
Thank you for considering contributing! Here’s how to get started:
|
|
4
|
-
|
|
5
|
-
## Branches
|
|
6
|
-
|
|
7
|
-
- `master`: Stable releases only.
|
|
8
|
-
- `dev`: All new features and fixes are merged here first.
|
|
9
|
-
- Create your feature/fix branch from `dev`:
|
|
10
|
-
- `feature/your-feature-name`
|
|
11
|
-
- `fix/your-bug-description`
|
|
12
|
-
|
|
13
|
-
## Workflow
|
|
14
|
-
|
|
15
|
-
1. Fork the repository.
|
|
16
|
-
2. Create your branch from `dev`.
|
|
17
|
-
3. Commit your changes with clear messages.
|
|
18
|
-
4. Open a Pull Request (PR) to `dev`.
|
|
19
|
-
5. Describe your changes and reference any related issues.
|
|
20
|
-
|
|
21
|
-
## Code Style
|
|
22
|
-
|
|
23
|
-
- Use TypeScript and follow existing formatting.
|
|
24
|
-
- Document your code with comments.
|
|
25
|
-
- Run `bun lint` and `bun test` before submitting.
|
|
26
|
-
|
|
27
|
-
## Issues
|
|
28
|
-
|
|
29
|
-
- Search for existing issues before opening a new one.
|
|
30
|
-
- Be clear and provide context, steps to reproduce, and screenshots if possible.
|
|
31
|
-
|
|
32
|
-
## Review & Merge
|
|
33
|
-
|
|
34
|
-
- All PRs are reviewed by maintainers or the community.
|
|
35
|
-
- Once approved, PRs are merged into `dev`, then into `master` for releases.
|
|
36
|
-
|
|
37
|
-
## Community
|
|
38
|
-
|
|
39
|
-
- Be respectful and constructive.
|
|
40
|
-
- Use GitHub Discussions for questions and ideas.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
Happy coding! 🚀
|
package/FONCTIONALITY.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Features of the create-next-pro binary
|
|
2
|
-
|
|
3
|
-
- Advanced Next.js project creation with options (TypeScript, ESLint, Tailwind, src/, Turbopack, i18n, import alias)
|
|
4
|
-
- `addpage` command:
|
|
5
|
-
- Add a page with templates (layout, page, loading, etc.)
|
|
6
|
-
- Automatically create folders/files in `src/app/[locale]` and `src/ui`
|
|
7
|
-
- Add translation files in `messages/<locale>`
|
|
8
|
-
- Supports nested pages (e.g. `PageParent.PageChild`)
|
|
9
|
-
- Creates in the parent folder
|
|
10
|
-
- Appends JSON to the parent object
|
|
11
|
-
- `addcomponent` command:
|
|
12
|
-
- Add a component to a page or globally
|
|
13
|
-
- Create the TSX file in `src/ui/<Page>/` or `src/ui/_global/`
|
|
14
|
-
- Add the component to the page or global translation JSON
|
|
15
|
-
- `rmpage` command:
|
|
16
|
-
- Remove a page and all its associated files
|
|
17
|
-
- Folders/files in `src/ui`, `src/app/[locale]`, and `messages/<locale>`
|
|
18
|
-
- Bash autocompletion:
|
|
19
|
-
- Suggests commands and existing pages
|
|
20
|
-
- Supports nested pages for completion
|
|
21
|
-
- Installation script proposed at first launch
|
|
22
|
-
- Fast CLI mode (non-interactive) and interactive mode (prompts)
|
|
23
|
-
- File generation from customizable templates
|
|
24
|
-
- Name handling (respects user input casing)
|
|
25
|
-
- Optional addition of the autocompletion script to `.bashrc` via prompt
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// README.mdThis is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-pro`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
|
2
|
-
|
|
3
|
-
## Getting Started
|
|
4
|
-
|
|
5
|
-
First, run the development server:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm run dev
|
|
9
|
-
# or
|
|
10
|
-
yarn dev
|
|
11
|
-
# or
|
|
12
|
-
pnpm dev
|
|
13
|
-
# or
|
|
14
|
-
bun dev
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
18
|
-
|
|
19
|
-
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
|
20
|
-
|
|
21
|
-
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
|
22
|
-
|
|
23
|
-
## Learn More
|
|
24
|
-
|
|
25
|
-
To learn more about Next.js, take a look at the following resources:
|
|
26
|
-
|
|
27
|
-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
|
28
|
-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
29
|
-
|
|
30
|
-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
|
31
|
-
|
|
32
|
-
## Deploy on Vercel
|
|
33
|
-
|
|
34
|
-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
|
35
|
-
|
|
36
|
-
Check out [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|