create-discordjs-nextgen 0.1.0 → 0.2.0
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 +3 -2
- package/bin/create-discordjs-nextgen.js +157 -69
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npx create-discordjs-nextgen my-bot
|
|
|
11
11
|
The CLI asks for:
|
|
12
12
|
|
|
13
13
|
- Language: `JavaScript` or `TypeScript`
|
|
14
|
-
- Plugins: `Voice`
|
|
14
|
+
- Plugins: `Voice`, `JSX`
|
|
15
15
|
- Template: `Starter Kit`, `Basic`, `Advanced`
|
|
16
16
|
|
|
17
17
|
## Templates
|
|
@@ -49,5 +49,6 @@ Creates a fuller example structure:
|
|
|
49
49
|
## Notes
|
|
50
50
|
|
|
51
51
|
- `Voice` adds `discordjs-nextgen-voice`
|
|
52
|
-
-
|
|
52
|
+
- `JSX` adds `discordjs-nextgen-jsx`, injects `app.use(new JSXPlugin())`, and creates one example prefix command
|
|
53
|
+
- TypeScript adds `ts-node`, `typescript`, `@types/node`
|
|
53
54
|
- Generated code follows the current `discordjs-nextgen` API
|
|
@@ -11,62 +11,68 @@ import pc from "picocolors";
|
|
|
11
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
12
|
const __dirname = path.dirname(__filename);
|
|
13
13
|
const templatesRoot = path.resolve(__dirname, "..", "templates");
|
|
14
|
+
const argv = process.argv.slice(2);
|
|
14
15
|
|
|
15
16
|
async function main() {
|
|
16
17
|
console.log("");
|
|
17
18
|
p.intro(`${pc.bgBlue(pc.white(" NEXTGEN-CLI "))} ${pc.dim("Modern Discord.js Framework")}`);
|
|
18
19
|
|
|
19
|
-
const
|
|
20
|
-
|
|
20
|
+
const cliProjectName = argv.find((arg) => !arg.startsWith("-"));
|
|
21
|
+
const forceJsx = argv.includes("--jsx");
|
|
22
|
+
|
|
23
|
+
const projectName = cliProjectName ?? await p.text({
|
|
24
|
+
message: "Proje adini ne koyalim?",
|
|
21
25
|
placeholder: "my-nextgen-bot",
|
|
22
26
|
validate(value) {
|
|
23
|
-
if (value.length === 0) return "
|
|
24
|
-
if (value.includes(" ")) return "Proje isminde
|
|
27
|
+
if (value.length === 0) return "Lutfen bir isim girin.";
|
|
28
|
+
if (value.includes(" ")) return "Proje isminde bosluk olamaz.";
|
|
25
29
|
},
|
|
26
30
|
});
|
|
27
31
|
|
|
28
32
|
if (p.isCancel(projectName)) {
|
|
29
|
-
p.cancel("
|
|
33
|
+
p.cancel("Islem iptal edildi.");
|
|
30
34
|
process.exit(0);
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
const language = await p.select({
|
|
34
38
|
message: "Hangi dili tercih edersiniz?",
|
|
35
39
|
options: [
|
|
36
|
-
{ value: "js", label: "JavaScript", hint: "Esnek ve
|
|
37
|
-
{ value: "ts", label: "TypeScript", hint: "Tip
|
|
40
|
+
{ value: "js", label: "JavaScript", hint: "Esnek ve hizli" },
|
|
41
|
+
{ value: "ts", label: "TypeScript", hint: "Tip guvenligi" },
|
|
38
42
|
],
|
|
39
43
|
});
|
|
40
44
|
|
|
41
45
|
if (p.isCancel(language)) {
|
|
42
|
-
p.cancel("
|
|
46
|
+
p.cancel("Islem iptal edildi.");
|
|
43
47
|
process.exit(0);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
const plugins = await p.multiselect({
|
|
47
|
-
message: "Eklemek
|
|
51
|
+
message: "Eklemek istediginiz pluginleri secin:",
|
|
48
52
|
options: [
|
|
49
|
-
{ value: "voice", label: "Voice Support", hint: "
|
|
53
|
+
{ value: "voice", label: "Voice Support", hint: "Muzik ve ses sistemleri" },
|
|
54
|
+
{ value: "jsx", label: "JSX Support", hint: "discordjs-nextgen-jsx ile JSX komutlar" },
|
|
50
55
|
],
|
|
56
|
+
initialValues: forceJsx ? ["jsx"] : [],
|
|
51
57
|
required: false,
|
|
52
58
|
});
|
|
53
59
|
|
|
54
60
|
if (p.isCancel(plugins)) {
|
|
55
|
-
p.cancel("
|
|
61
|
+
p.cancel("Islem iptal edildi.");
|
|
56
62
|
process.exit(0);
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
const template = await p.select({
|
|
60
|
-
message: "Hangi
|
|
66
|
+
message: "Hangi sablonla baslamak istersiniz?",
|
|
61
67
|
options: [
|
|
62
|
-
{ value: "starter", label: "Starter Kit", hint: "
|
|
63
|
-
{ value: "basic", label: "Basic", hint: "
|
|
64
|
-
{ value: "advanced", label: "Advanced", hint: "
|
|
68
|
+
{ value: "starter", label: "Starter Kit", hint: "Minimum kurulum" },
|
|
69
|
+
{ value: "basic", label: "Basic", hint: "Basit komutlar ve olaylar" },
|
|
70
|
+
{ value: "advanced", label: "Advanced", hint: "Buttons, modals, selects dahil" },
|
|
65
71
|
],
|
|
66
72
|
});
|
|
67
73
|
|
|
68
74
|
if (p.isCancel(template)) {
|
|
69
|
-
p.cancel("
|
|
75
|
+
p.cancel("Islem iptal edildi.");
|
|
70
76
|
process.exit(0);
|
|
71
77
|
}
|
|
72
78
|
|
|
@@ -77,8 +83,8 @@ async function main() {
|
|
|
77
83
|
|
|
78
84
|
try {
|
|
79
85
|
if (fs.existsSync(targetDir) && (await fsp.readdir(targetDir)).length > 0) {
|
|
80
|
-
s.stop(pc.red("Hata
|
|
81
|
-
p.log.error(`
|
|
86
|
+
s.stop(pc.red("Hata"));
|
|
87
|
+
p.log.error(`'${projectName}' klasoru zaten var ve bos degil.`);
|
|
82
88
|
process.exit(1);
|
|
83
89
|
}
|
|
84
90
|
|
|
@@ -88,33 +94,42 @@ async function main() {
|
|
|
88
94
|
|
|
89
95
|
await generateProject(targetDir, { projectName, language, template, plugins });
|
|
90
96
|
|
|
91
|
-
s.stop(pc.green("Proje
|
|
97
|
+
s.stop(pc.green("Proje basariyla olusturuldu."));
|
|
92
98
|
|
|
93
99
|
const shouldInstall = await p.confirm({
|
|
94
|
-
message: "
|
|
100
|
+
message: "Bagimliliklari simdi kurmak ister misiniz?",
|
|
95
101
|
initialValue: true,
|
|
96
102
|
});
|
|
97
103
|
|
|
98
104
|
if (shouldInstall) {
|
|
99
105
|
const installSpinner = p.spinner();
|
|
100
|
-
installSpinner.start(pc.yellow("Paketler
|
|
106
|
+
installSpinner.start(pc.yellow("Paketler yukleniyor..."));
|
|
101
107
|
const success = await runInstall(targetDir);
|
|
102
108
|
if (success) {
|
|
103
|
-
installSpinner.stop(pc.green("Kurulum
|
|
109
|
+
installSpinner.stop(pc.green("Kurulum tamamlandi."));
|
|
104
110
|
} else {
|
|
105
|
-
installSpinner.stop(pc.red("Kurulum
|
|
111
|
+
installSpinner.stop(pc.red("Kurulum basarisiz oldu."));
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"Sıradaki Adımlar"
|
|
112
|
-
);
|
|
115
|
+
const runCommand = language === "ts" ? "npm run dev" : "npm run dev";
|
|
116
|
+
p.note(`cd ${projectName}\n${!shouldInstall ? "npm install\n" : ""}${runCommand}`, "Siradaki Adimlar");
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
const pluginNotes = [];
|
|
119
|
+
if (plugins.includes("jsx")) {
|
|
120
|
+
pluginNotes.push(
|
|
121
|
+
language === "ts"
|
|
122
|
+
? "JSX aktif: tsconfig.json yazildi, index dosyasina JSXPlugin eklendi, commands/prefix/hello.tsx olusturuldu."
|
|
123
|
+
: "JSX aktif: jsconfig.json yazildi, index dosyasina JSXPlugin eklendi, commands/prefix/hello.jsx olusturuldu."
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
if (pluginNotes.length > 0) {
|
|
127
|
+
p.note(pluginNotes.join("\n"), "Bilgi");
|
|
128
|
+
}
|
|
115
129
|
|
|
130
|
+
p.outro(pc.blue("Iyi kodlamalar."));
|
|
116
131
|
} catch (err) {
|
|
117
|
-
s.stop(pc.red("Bir hata
|
|
132
|
+
s.stop(pc.red("Bir hata olustu."));
|
|
118
133
|
console.error(err);
|
|
119
134
|
process.exit(1);
|
|
120
135
|
}
|
|
@@ -134,50 +149,85 @@ async function generateProject(targetDir, config) {
|
|
|
134
149
|
version: "1.0.0",
|
|
135
150
|
private: true,
|
|
136
151
|
type: "module",
|
|
137
|
-
scripts: config.language === "ts"
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
152
|
+
scripts: config.language === "ts"
|
|
153
|
+
? {
|
|
154
|
+
dev: "ts-node index.ts",
|
|
155
|
+
start: "ts-node index.ts",
|
|
156
|
+
build: "tsc",
|
|
157
|
+
}
|
|
158
|
+
: {
|
|
159
|
+
dev: "node index.js",
|
|
160
|
+
start: "node index.js",
|
|
161
|
+
},
|
|
145
162
|
dependencies: {
|
|
146
163
|
"discordjs-nextgen": "latest",
|
|
147
|
-
"dotenv": "^17.3.1"
|
|
148
|
-
}
|
|
164
|
+
"dotenv": "^17.3.1",
|
|
165
|
+
},
|
|
149
166
|
};
|
|
150
167
|
|
|
151
168
|
if (config.language === "ts") {
|
|
152
169
|
pkg.devDependencies = {
|
|
153
170
|
"@types/node": "^20.12.0",
|
|
154
171
|
"ts-node": "^10.9.2",
|
|
155
|
-
"typescript": "^5.4.5"
|
|
172
|
+
"typescript": "^5.4.5",
|
|
156
173
|
};
|
|
157
|
-
await writeFile(targetDir, "tsconfig.json", JSON.stringify({
|
|
158
|
-
compilerOptions: {
|
|
159
|
-
target: "ESNext",
|
|
160
|
-
module: "ESNext",
|
|
161
|
-
moduleResolution: "node",
|
|
162
|
-
esModuleInterop: true,
|
|
163
|
-
strict: true,
|
|
164
|
-
skipLibCheck: true,
|
|
165
|
-
outDir: "dist"
|
|
166
|
-
}
|
|
167
|
-
}, null, 2));
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
if (config.plugins.includes("voice")) {
|
|
171
177
|
pkg.dependencies["discordjs-nextgen-voice"] = "latest";
|
|
172
178
|
}
|
|
173
179
|
|
|
180
|
+
if (config.plugins.includes("jsx")) {
|
|
181
|
+
pkg.dependencies["discordjs-nextgen-jsx"] = "latest";
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
await writeLanguageConfig(targetDir, config.language, config.plugins.includes("jsx"));
|
|
174
185
|
await writeFile(targetDir, "package.json", JSON.stringify(pkg, null, 2));
|
|
175
186
|
await writeFile(targetDir, ".gitignore", "node_modules\n.env\ndist\n");
|
|
176
|
-
await writeFile(targetDir, ".env", "TOKEN=YOUR_BOT_TOKEN_HERE");
|
|
187
|
+
await writeFile(targetDir, ".env", "TOKEN=YOUR_BOT_TOKEN_HERE\n");
|
|
177
188
|
|
|
178
189
|
if (config.plugins.includes("voice")) {
|
|
179
190
|
await injectVoicePlugin(targetDir, extension, config.template);
|
|
180
191
|
}
|
|
192
|
+
|
|
193
|
+
if (config.plugins.includes("jsx")) {
|
|
194
|
+
await injectJSXPlugin(targetDir, config.language);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function writeLanguageConfig(targetDir, language, useJsx) {
|
|
199
|
+
if (language === "ts") {
|
|
200
|
+
const tsconfig = {
|
|
201
|
+
compilerOptions: {
|
|
202
|
+
target: "ESNext",
|
|
203
|
+
module: "ESNext",
|
|
204
|
+
moduleResolution: "node",
|
|
205
|
+
esModuleInterop: true,
|
|
206
|
+
strict: true,
|
|
207
|
+
skipLibCheck: true,
|
|
208
|
+
outDir: "dist",
|
|
209
|
+
},
|
|
210
|
+
include: ["**/*"],
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
if (useJsx) {
|
|
214
|
+
tsconfig.compilerOptions.jsx = "react-jsx";
|
|
215
|
+
tsconfig.compilerOptions.jsxImportSource = "discordjs-nextgen-jsx";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await writeFile(targetDir, "tsconfig.json", JSON.stringify(tsconfig, null, 2));
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (useJsx) {
|
|
223
|
+
await writeFile(targetDir, "jsconfig.json", JSON.stringify({
|
|
224
|
+
compilerOptions: {
|
|
225
|
+
jsx: "react-jsx",
|
|
226
|
+
jsxImportSource: "discordjs-nextgen-jsx",
|
|
227
|
+
},
|
|
228
|
+
include: ["**/*"],
|
|
229
|
+
}, null, 2));
|
|
230
|
+
}
|
|
181
231
|
}
|
|
182
232
|
|
|
183
233
|
async function injectVoicePlugin(targetDir, extension, template) {
|
|
@@ -185,27 +235,59 @@ async function injectVoicePlugin(targetDir, extension, template) {
|
|
|
185
235
|
let content = await fsp.readFile(entryPath, "utf8");
|
|
186
236
|
|
|
187
237
|
const importLine = `import { VoicePlugin } from "discordjs-nextgen-voice";`;
|
|
188
|
-
const useLine = `\napp.use(new VoicePlugin());`;
|
|
189
238
|
|
|
190
239
|
if (!content.includes(importLine)) {
|
|
191
240
|
content = `${importLine}\n${content}`;
|
|
192
241
|
}
|
|
193
242
|
|
|
194
243
|
if (!content.includes("new VoicePlugin()")) {
|
|
195
|
-
content = content.replace(/const app = new App\((\{[\s\S]*?\}|)\);/, (match) => `${match}\n
|
|
244
|
+
content = content.replace(/const app = new App\((\{[\s\S]*?\}|)\);/, (match) => `${match}\n\napp.use(new VoicePlugin());`);
|
|
196
245
|
}
|
|
197
246
|
|
|
198
247
|
await fsp.writeFile(entryPath, content, "utf8");
|
|
199
248
|
|
|
200
249
|
if (template !== "starter") {
|
|
201
|
-
const cmdCode = `export default {\n name: "join",\n description: "Sese girer.",\n run: async (ctx) => {\n await ctx.voice.join({ channelId: ctx.member.voice.channelId });\n }\n}
|
|
202
|
-
await writeFile(targetDir,
|
|
250
|
+
const cmdCode = `export default {\n name: "join",\n description: "Sese girer.",\n run: async (ctx) => {\n await ctx.voice.join({ channelId: ctx.member.voice.channelId });\n }\n};\n`;
|
|
251
|
+
await writeFile(targetDir, `commands/prefix/join.${extension}`, cmdCode);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async function injectJSXPlugin(targetDir, language) {
|
|
256
|
+
const entryExtension = language === "ts" ? "ts" : "js";
|
|
257
|
+
const jsxExtension = language === "ts" ? "tsx" : "jsx";
|
|
258
|
+
const entryPath = path.join(targetDir, `index.${entryExtension}`);
|
|
259
|
+
let content = await fsp.readFile(entryPath, "utf8");
|
|
260
|
+
|
|
261
|
+
const importLine = `import { JSXPlugin } from "discordjs-nextgen-jsx";`;
|
|
262
|
+
|
|
263
|
+
if (!content.includes(importLine)) {
|
|
264
|
+
content = `${importLine}\n${content}`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (!content.includes("new JSXPlugin()")) {
|
|
268
|
+
content = content.replace(/const app = new App\((\{[\s\S]*?\}|)\);/, (match) => `${match}\n\napp.use(new JSXPlugin());`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (!content.includes(".prefix(")) {
|
|
272
|
+
content = content.replace(
|
|
273
|
+
/app\.setPresence\(/,
|
|
274
|
+
`app.prefix({\n folder: 'commands/prefix',\n prefix: '.',\n});\n\napp.setPresence(`
|
|
275
|
+
);
|
|
203
276
|
}
|
|
277
|
+
|
|
278
|
+
await fsp.writeFile(entryPath, content, "utf8");
|
|
279
|
+
|
|
280
|
+
const jsxPrefixCommand = language === "ts"
|
|
281
|
+
? `import type { PrefixCommand } from 'discordjs-nextgen';\nimport { Container, TextDisplay } from 'discordjs-nextgen-jsx';\n\nconst hello: PrefixCommand = {\n name: 'hello',\n description: 'JSX example command',\n run: async (ctx) => {\n const card = (\n <Container accentColor={0x5865f2}>\n <TextDisplay content="Hello from JSX." />\n <TextDisplay content={\`Author: \${ctx.user.username}\`} />\n </Container>\n );\n\n await ctx.reply({\n components: [card],\n });\n },\n};\n\nexport default hello;\n`
|
|
282
|
+
: `import { Container, TextDisplay } from 'discordjs-nextgen-jsx';\n\nconst hello = {\n name: 'hello',\n description: 'JSX example command',\n run: async (ctx) => {\n const card = (\n <Container accentColor={0x5865f2}>\n <TextDisplay content="Hello from JSX." />\n <TextDisplay content={\`Author: \${ctx.user.username}\`} />\n </Container>\n );\n\n await ctx.reply({\n components: [card],\n });\n },\n};\n\nexport default hello;\n`;
|
|
283
|
+
|
|
284
|
+
await writeFile(targetDir, `commands/prefix/hello.${jsxExtension}`, jsxPrefixCommand);
|
|
204
285
|
}
|
|
205
286
|
|
|
206
287
|
async function copyTemplateDirectory(sourceDir, targetDir, context) {
|
|
207
288
|
if (!fs.existsSync(sourceDir)) return;
|
|
208
289
|
const entries = await fsp.readdir(sourceDir, { withFileTypes: true });
|
|
290
|
+
|
|
209
291
|
for (const entry of entries) {
|
|
210
292
|
const src = path.join(sourceDir, entry.name);
|
|
211
293
|
const destName = entry.name.replace(/__EXT__/g, context.extension);
|
|
@@ -214,20 +296,21 @@ async function copyTemplateDirectory(sourceDir, targetDir, context) {
|
|
|
214
296
|
if (entry.isDirectory()) {
|
|
215
297
|
await fsp.mkdir(dest, { recursive: true });
|
|
216
298
|
await copyTemplateDirectory(src, dest, context);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
content = content.replace(/\/\/ \[JS\][\s\S]*?\/\/ \[\/JS\]/g, "");
|
|
222
|
-
content = content.replace(/\/\/ \[TS\]/g, "").replace(/\/\/ \[\/TS\]/g, "");
|
|
223
|
-
} else {
|
|
224
|
-
content = content.replace(/\/\/ \[TS\][\s\S]*?\/\/ \[\/TS\]/g, "");
|
|
225
|
-
content = content.replace(/\/\/ \[JS\]/g, "").replace(/\/\/ \[\/JS\]/g, "");
|
|
226
|
-
}
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
let content = await fsp.readFile(src, "utf8");
|
|
227
303
|
|
|
228
|
-
|
|
229
|
-
|
|
304
|
+
if (context.language === "ts") {
|
|
305
|
+
content = content.replace(/\/\/ \[JS\][\s\S]*?\/\/ \[\/JS\]/g, "");
|
|
306
|
+
content = content.replace(/\/\/ \[TS\]/g, "").replace(/\/\/ \[\/TS\]/g, "");
|
|
307
|
+
} else {
|
|
308
|
+
content = content.replace(/\/\/ \[TS\][\s\S]*?\/\/ \[\/TS\]/g, "");
|
|
309
|
+
content = content.replace(/\/\/ \[JS\]/g, "").replace(/\/\/ \[\/JS\]/g, "");
|
|
230
310
|
}
|
|
311
|
+
|
|
312
|
+
content = content.replaceAll("__EXT__", context.extension);
|
|
313
|
+
await fsp.writeFile(dest, content, "utf8");
|
|
231
314
|
}
|
|
232
315
|
}
|
|
233
316
|
|
|
@@ -238,7 +321,12 @@ async function writeFile(baseDir, relPath, content) {
|
|
|
238
321
|
}
|
|
239
322
|
|
|
240
323
|
async function runInstall(targetDir) {
|
|
241
|
-
const result = spawnSync("npm", ["install"], {
|
|
324
|
+
const result = spawnSync("npm", ["install"], {
|
|
325
|
+
cwd: targetDir,
|
|
326
|
+
stdio: "inherit",
|
|
327
|
+
shell: true,
|
|
328
|
+
});
|
|
329
|
+
|
|
242
330
|
return result.status === 0;
|
|
243
331
|
}
|
|
244
332
|
|