create-craftjs 1.0.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.
Files changed (66) hide show
  1. package/README.md +137 -0
  2. package/bin/index.js +158 -0
  3. package/package.json +24 -0
  4. package/template/.dockerignore +4 -0
  5. package/template/Dockerfile +12 -0
  6. package/template/babel.config.json +3 -0
  7. package/template/craft/commands/build.js +15 -0
  8. package/template/craft/commands/db-fresh.js +22 -0
  9. package/template/craft/commands/db-generate.js +23 -0
  10. package/template/craft/commands/db-migrate.js +22 -0
  11. package/template/craft/commands/dev.js +16 -0
  12. package/template/craft/commands/key-generate.js +41 -0
  13. package/template/craft/commands/make-apidocs.js +121 -0
  14. package/template/craft/commands/make-command.js +38 -0
  15. package/template/craft/commands/make-dto.js +39 -0
  16. package/template/craft/commands/make-middleware.js +46 -0
  17. package/template/craft/commands/make-repository.js +36 -0
  18. package/template/craft/commands/make-route.js +88 -0
  19. package/template/craft/commands/make-service.js +39 -0
  20. package/template/craft/commands/make-test.js +48 -0
  21. package/template/craft/commands/make-utils.js +30 -0
  22. package/template/craft/commands/make-validation.js +42 -0
  23. package/template/craft/commands/make-view.js +42 -0
  24. package/template/craft/commands/start.js +29 -0
  25. package/template/craft/commands/test.js +20 -0
  26. package/template/craft.js +256 -0
  27. package/template/nodemon.json +6 -0
  28. package/template/package-lock.json +8777 -0
  29. package/template/package.json +79 -0
  30. package/template/prisma/migrations/20250518142257_create_table_users/migration.sql +13 -0
  31. package/template/prisma/migrations/migration_lock.toml +3 -0
  32. package/template/prisma/schema.prisma +22 -0
  33. package/template/prisma/seed.ts +29 -0
  34. package/template/public/assets/images/default-user.png +0 -0
  35. package/template/src/apidocs/auth-docs.ts +314 -0
  36. package/template/src/apidocs/users-docs.ts +240 -0
  37. package/template/src/config/database.ts +90 -0
  38. package/template/src/config/env.ts +29 -0
  39. package/template/src/config/logger.ts +116 -0
  40. package/template/src/config/web.ts +40 -0
  41. package/template/src/controllers/auth-controller.ts +88 -0
  42. package/template/src/controllers/user-controller.ts +79 -0
  43. package/template/src/dtos/list-dto.ts +12 -0
  44. package/template/src/dtos/user-dto.ts +57 -0
  45. package/template/src/main.ts +28 -0
  46. package/template/src/middleware/auth-middleware.ts +44 -0
  47. package/template/src/middleware/error-middleware.ts +27 -0
  48. package/template/src/middleware/http-logger-middleware.ts +31 -0
  49. package/template/src/repositories/user-repository.ts +75 -0
  50. package/template/src/routes/auth-route.ts +20 -0
  51. package/template/src/routes/main-route.ts +25 -0
  52. package/template/src/routes/user-route.ts +35 -0
  53. package/template/src/services/auth-service.ts +162 -0
  54. package/template/src/services/user-service.ts +102 -0
  55. package/template/src/types/type-request.ts +6 -0
  56. package/template/src/utils/async-handler.ts +9 -0
  57. package/template/src/utils/response-error.ts +10 -0
  58. package/template/src/utils/response.ts +60 -0
  59. package/template/src/utils/swagger.ts +135 -0
  60. package/template/src/utils/validation.ts +7 -0
  61. package/template/src/validations/user-validation.ts +127 -0
  62. package/template/src/views/index.ejs +6 -0
  63. package/template/src/views/layouts/main.ejs +14 -0
  64. package/template/src/views/partials/header.ejs +3 -0
  65. package/template/test/user.test.ts +16 -0
  66. package/template/tsconfig.json +13 -0
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # CraftJS
2
+
3
+ A starter kit backend framework powered by Express, TypeScript, EJS Engine, and Prisma — designed for rapid development, simplicity, and scalability.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - **Express.js** based API architecture
10
+ - **TypeScript** support out of the box
11
+ - **Prisma ORM** with scalable database structure
12
+ - **CLI tool** (`craft`) for project automation
13
+ - Built-in **Logger**, **Validation**, **Error handler**, and **Request lifecycle**
14
+ - Predefined project structure for fast onboarding
15
+
16
+ ---
17
+
18
+ 💡 Note: EJS View Engine is included but disabled by default. To enable it:
19
+ Open src/application/web.ts and uncomment the following lines:
20
+
21
+ ```bash
22
+ import expressLayouts from "express-ejs-layouts";
23
+ import path from "path";
24
+
25
+ web.set("view engine", "ejs");
26
+ web.set("views", path.join(\_\_dirname, "..", "views"));
27
+ web.use(expressLayouts);
28
+ web.set("layout", "layouts/main");
29
+ ```
30
+
31
+ Then, go to src/routes/main-route.ts and uncomment this:
32
+
33
+ ```bash
34
+ mainRouter.get("/", (req, res) => {
35
+ res.render("index", { title: "Home Page" });
36
+ });
37
+ ```
38
+
39
+ ## Getting Started
40
+
41
+ ### Scaffold a New Project
42
+
43
+ ```bash
44
+ npx create-craftjs my-app
45
+ ```
46
+
47
+ OR
48
+
49
+ ```bash
50
+ npm init craftjs my-app
51
+ ```
52
+
53
+ ### Go to project folder
54
+
55
+ ```bash
56
+ cd my-app
57
+ ```
58
+
59
+ ### Run Craft Setup
60
+
61
+ ```bash
62
+ npm install
63
+ node craft key:generate
64
+ node craft generate
65
+ node craft db:migrate
66
+ node craft dev
67
+ ```
68
+
69
+ ### Available Craft Commands
70
+
71
+ ```bash
72
+ node craft help
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Project Structure
78
+
79
+ ```
80
+ my-app/
81
+ ├── craft/
82
+ ├── src/
83
+ │ ├── apidocs/
84
+ │ ├── config/
85
+ │ ├── controllers/
86
+ │ ├── middleware/
87
+ │ ├── repositories/
88
+ │ ├── dtos/
89
+ │ ├── routes/
90
+ │ └── services/
91
+ │ └── types/
92
+ │ └── utils/
93
+ │ └── validations/
94
+ │ └── main.ts
95
+ ├── test/
96
+ ├── logs/
97
+ ├── .env
98
+ ├── .env.example
99
+ ├── prisma/
100
+ ├── .gitignore
101
+ ├── babel.config.json
102
+ ├── craft.js
103
+ ├── nodemon.json
104
+ ├── package.json
105
+ ├── package-lock.json
106
+ └── tsconfig.json
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Scripts
112
+
113
+ | Command | Description |
114
+ | ----------------------- | ------------------------------ |
115
+ | `craft start` | Start production server |
116
+ | `craft dev` | Run in development mode |
117
+ | `craft build` | Build for production |
118
+ | `craft test` | Run Jest tests |
119
+ | `craft db:generate` | Generate Prisma client |
120
+ | `craft db:migrate` | Run Prisma migrations |
121
+ | `craft db:reset` | Run Prisma migrations refresh |
122
+ | `craft key:generate` | Generate secret keys |
123
+ | `craft make:controller` | Make Controller File |
124
+ | `craft make:command` | Make Command File |
125
+ | `craft make:middleware` | Make Middleware File |
126
+ | `craft make:repository` | Make repository File |
127
+ | `craft make:dto` | Make Data Transfer Object File |
128
+ | `craft make:route` | Make Route File |
129
+ | `craft make:service` | Make Service File |
130
+ | `craft make:test` | Make Test case |
131
+ | `craft make:utils` | Make Utils |
132
+ | `craft make:validation` | Make Validation |
133
+ | `craft make:view` | Make View |
134
+
135
+ ---
136
+
137
+ Made by [@muhammadisa-n](https://github.com/muhammadisa-n)
package/bin/index.js ADDED
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { spawnSync } = require("child_process");
6
+ const readline = require("readline");
7
+
8
+ const rl = readline.createInterface({
9
+ input: process.stdin,
10
+ output: process.stdout,
11
+ });
12
+
13
+ const ask = (question) => {
14
+ return new Promise((resolve) => {
15
+ rl.question(question, (answer) => resolve(answer.trim()));
16
+ });
17
+ };
18
+
19
+ (async () => {
20
+ console.log("🚀 Welcome to CraftJS Project Creator!");
21
+
22
+ let projectName = process.argv[2];
23
+
24
+ if (!projectName) {
25
+ projectName = await ask("📦 Enter your project name: ");
26
+ while (!projectName || !/^[a-zA-Z0-9-_]+$/.test(projectName)) {
27
+ console.log(
28
+ "❌ Invalid project name. Use only letters, numbers, - and _."
29
+ );
30
+ projectName = await ask("📦 Enter your project name: ");
31
+ }
32
+ } else {
33
+ if (!/^[a-zA-Z0-9-_]+$/.test(projectName)) {
34
+ console.error(
35
+ "❌ Project name can only contain letters, numbers, dashes (-), and underscores (_)."
36
+ );
37
+ rl.close();
38
+ process.exit(1);
39
+ }
40
+ }
41
+
42
+ const targetPath = path.resolve(process.cwd(), projectName);
43
+ const templatePath = path.join(__dirname, "..", "template");
44
+
45
+ if (fs.existsSync(targetPath)) {
46
+ console.error(`❌ Folder "${projectName}" already exists.`);
47
+ rl.close();
48
+ process.exit(1);
49
+ }
50
+
51
+ const copyRecursiveSync = (src, dest) => {
52
+ const entries = fs.readdirSync(src, { withFileTypes: true });
53
+ fs.mkdirSync(dest, { recursive: true });
54
+
55
+ for (let entry of entries) {
56
+ const srcPath = path.join(src, entry.name);
57
+ const destPath = path.join(dest, entry.name);
58
+ if (entry.isDirectory()) {
59
+ copyRecursiveSync(srcPath, destPath);
60
+ } else {
61
+ fs.copyFileSync(srcPath, destPath);
62
+ }
63
+ }
64
+ };
65
+
66
+ console.log(`\n🚧 Creating project in ./${projectName}...`);
67
+ copyRecursiveSync(templatePath, targetPath);
68
+
69
+ const packageJsonPath = path.join(targetPath, "package.json");
70
+ if (fs.existsSync(packageJsonPath)) {
71
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
72
+ pkg.name = projectName;
73
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2));
74
+ console.log(`📦 Updated package.json name to "${projectName}"`);
75
+ }
76
+
77
+ const envContent = `APP_NAME="${projectName}"
78
+ APP_SECRET=
79
+ NODE_ENV="development"
80
+ TZ="Asia/Jakarta"
81
+ DATETIME_FORMAT="dd-MM-yyyy HH:mm:ss"
82
+ DATABASE_URL="mysql://root:@localhost:3306/${projectName}"
83
+ BASE_URL="http://localhost:3000"
84
+ BASE_API_URL="http://localhost:3000/api"
85
+ PORT=3000
86
+ JWT_SECRET=
87
+ `;
88
+
89
+ const envExampleContent = envContent.replace(/=.*/g, "=");
90
+
91
+ const sourceReadmePath = path.join(__dirname, "..", "README.md");
92
+ const targetReadmePath = path.join(targetPath, "README.md");
93
+
94
+ if (fs.existsSync(sourceReadmePath)) {
95
+ fs.copyFileSync(sourceReadmePath, targetReadmePath);
96
+ console.log("📄 Copied README.md...");
97
+ }
98
+
99
+ console.log("📝 Generating .env and .env.example...");
100
+ fs.writeFileSync(path.join(targetPath, ".env"), envContent);
101
+ fs.writeFileSync(path.join(targetPath, ".env.example"), envExampleContent);
102
+
103
+ console.log("🔧 Initializing git repository...");
104
+ const gitInit = spawnSync("git", ["init"], {
105
+ cwd: targetPath,
106
+ stdio: "inherit",
107
+ shell: true,
108
+ });
109
+
110
+ if (gitInit.status !== 0) {
111
+ console.warn("⚠️ Git initialization failed.");
112
+ }
113
+
114
+ const gitignorePath = path.join(targetPath, ".gitignore");
115
+ if (!fs.existsSync(gitignorePath)) {
116
+ fs.writeFileSync(
117
+ gitignorePath,
118
+ `node_modules
119
+ .env
120
+ dist
121
+ `
122
+ );
123
+ }
124
+
125
+ const installNow = await ask(
126
+ "📥 Do you want to install dependencies now? (yes/no): "
127
+ );
128
+ if (installNow.toLowerCase() === "yes" || installNow.toLowerCase() === "y") {
129
+ console.log("📦 Installing dependencies...");
130
+ const npmInstall = spawnSync("npm", ["install"], {
131
+ cwd: targetPath,
132
+ stdio: "inherit",
133
+ shell: true,
134
+ });
135
+
136
+ if (npmInstall.status !== 0) {
137
+ console.warn("⚠️ npm install failed.");
138
+ console.log("\n✅ Done!");
139
+ console.log(
140
+ `\nNext steps:\n cd ${projectName}\n npm install\n node craft key:generate\n node craft db:generate\n node craft db:migrate\n node craft dev`
141
+ );
142
+ } else {
143
+ console.log("✅ Dependencies installed successfully.");
144
+ console.log("\n✅ Done!");
145
+ console.log(
146
+ `\nNext steps:\n cd ${projectName}\n node craft key:generate\n node craft db:generate\n node craft db:migrate\n node craft dev`
147
+ );
148
+ }
149
+ } else {
150
+ console.log("ℹ️ Skipping dependency installation.");
151
+ console.log("\n✅ Done!");
152
+ console.log(
153
+ `\nNext steps:\n cd ${projectName}\n npm install\n node craft key:generate\n node craft db:generate\n node craft db:migrate\n node craft dev`
154
+ );
155
+ }
156
+
157
+ rl.close();
158
+ })();
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "create-craftjs",
3
+ "version": "1.0.0",
4
+ "description": "A starter kit backend framework powered by Express, TypeScript, EJS Engine, and Prisma — designed for rapid development, simplicity, and scalability.",
5
+ "bin": {
6
+ "create-craftjs": "bin/index.js"
7
+ },
8
+ "author": "Muhammad Isa Nuruddin",
9
+ "homepage": "https://github.com/muhammadisa-n/CraftJS#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/muhammadisa-n/CraftJS/issues"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/muhammadisa-n/CraftJS.git"
16
+ },
17
+ "license": "UNLICENSED",
18
+ "keywords": [
19
+ "express",
20
+ "typescript",
21
+ "prisma",
22
+ "api"
23
+ ]
24
+ }
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ dist
3
+ Dockerfile
4
+ .dockerignore
@@ -0,0 +1,12 @@
1
+ FROM node:20
2
+ WORKDIR /usr/src/app
3
+ COPY package*.json ./
4
+ RUN npm install
5
+ COPY prisma ./prisma
6
+ RUN npx prisma generate
7
+ COPY . .
8
+ COPY .env .env
9
+ RUN npm install typescript
10
+ RUN npm run build
11
+ EXPOSE 3000
12
+ CMD ["npm", "run", "dev"]
@@ -0,0 +1,3 @@
1
+ {
2
+ "presets": ["@babel/preset-env", "@babel/preset-typescript"]
3
+ }
@@ -0,0 +1,15 @@
1
+ const { execSync } = require("child_process");
2
+ const chalk = require("chalk");
3
+ function Build() {
4
+ console.log(chalk.blue("📦 Building project..."));
5
+
6
+ try {
7
+ execSync("npx tsc && cp -r src/views dist/views", { stdio: "inherit" });
8
+ console.log(chalk.green("✅ Build completed successfully."));
9
+ } catch (error) {
10
+ console.error(chalk.red("❌ Build failed."));
11
+ process.exit(1);
12
+ }
13
+ }
14
+
15
+ module.exports = Build;
@@ -0,0 +1,22 @@
1
+ const { spawnSync } = require("child_process");
2
+ const chalk = require("chalk");
3
+
4
+ function DbReset() {
5
+ console.log(chalk.blue("🚀 Running prisma migrate reset..."));
6
+
7
+ const result = spawnSync("npx", ["prisma", "migrate", "reset"], {
8
+ stdio: "inherit",
9
+ shell: true,
10
+ });
11
+
12
+ if (result.status !== 0) {
13
+ console.error(chalk.red("❌ Migrate reset failed."));
14
+ if (result.error) {
15
+ console.error(chalk.red(`Error: ${result.error.message}`));
16
+ }
17
+ process.exit(result.status ?? 1);
18
+ } else {
19
+ console.log(chalk.green("✅ Migrate reset completed."));
20
+ }
21
+ }
22
+ module.exports = DbReset;
@@ -0,0 +1,23 @@
1
+ const { spawnSync } = require("child_process");
2
+ const chalk = require("chalk");
3
+
4
+ function DbGenerate() {
5
+ console.log(chalk.blue("🚀 Running prisma generate..."));
6
+
7
+ const result = spawnSync("npx", ["prisma", "generate"], {
8
+ stdio: "inherit",
9
+ shell: true,
10
+ });
11
+
12
+ if (result.status !== 0) {
13
+ console.error(chalk.red("❌ Generate failed."));
14
+ // Jika ada error, print detailnya
15
+ if (result.error) {
16
+ console.error(chalk.red(`Error: ${result.error.message}`));
17
+ }
18
+ process.exit(result.status ?? 1);
19
+ } else {
20
+ console.log(chalk.green("✅ Prisma generate completed."));
21
+ }
22
+ }
23
+ module.exports = DbGenerate;
@@ -0,0 +1,22 @@
1
+ const { spawnSync } = require("child_process");
2
+ const chalk = require("chalk");
3
+
4
+ function DbMigrate() {
5
+ console.log(chalk.blue("🚀 Running prisma migrate dev..."));
6
+
7
+ const result = spawnSync("npx", ["prisma", "migrate", "dev"], {
8
+ stdio: "inherit",
9
+ shell: true,
10
+ });
11
+
12
+ if (result.status !== 0) {
13
+ console.error(chalk.red("❌ Migration failed."));
14
+ if (result.error) {
15
+ console.error(chalk.red(`Error: ${result.error.message}`));
16
+ }
17
+ process.exit(result.status ?? 1);
18
+ } else {
19
+ console.log(chalk.green("✅ Migration completed."));
20
+ }
21
+ }
22
+ module.exports = DbMigrate;
@@ -0,0 +1,16 @@
1
+ const { spawnSync } = require("child_process");
2
+ const chalk = require("chalk");
3
+
4
+ function Dev() {
5
+ console.log(chalk.blue("🚀 Starting development server with nodemon..."));
6
+ const result = spawnSync("nodemon", ["./src/main.ts"], {
7
+ stdio: "inherit",
8
+ shell: true,
9
+ });
10
+
11
+ if (result.status !== 0) {
12
+ console.error(chalk.red("❌ Failed to start development server."));
13
+ process.exit(result.status ?? 1);
14
+ }
15
+ }
16
+ module.exports = Dev;
@@ -0,0 +1,41 @@
1
+ const chalk = require("chalk");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const crypto = require("crypto");
5
+
6
+ function keyGenerate() {
7
+ const envPath = path.resolve(process.cwd(), ".env");
8
+ if (!fs.existsSync(envPath)) {
9
+ console.error(chalk.red("❌ .env file not found!"));
10
+ process.exit(1);
11
+ }
12
+
13
+ let envContent = fs.readFileSync(envPath, "utf-8");
14
+
15
+ const generateKey = (number) => crypto.randomBytes(number).toString("hex");
16
+
17
+ if (envContent.includes("JWT_SECRET=")) {
18
+ envContent = envContent.replace(
19
+ /JWT_SECRET=.*/g,
20
+ `JWT_SECRET=${generateKey(16)}`
21
+ );
22
+ } else {
23
+ envContent += `\nJWT_SECRET_ACCESS_TOKEN=${generateKey(16)}`;
24
+ }
25
+
26
+ if (envContent.includes("APP_SECRET=")) {
27
+ envContent = envContent.replace(
28
+ /APP_SECRET=.*/g,
29
+ `APP_SECRET=${generateKey(32)}`
30
+ );
31
+ } else {
32
+ envContent += `\APP_SECRET=${generateKey(32)}`;
33
+ }
34
+
35
+ fs.writeFileSync(envPath, envContent);
36
+
37
+ console.log(
38
+ chalk.green("✅ App Secret and JWT Secret generated successfully.")
39
+ );
40
+ }
41
+ module.exports = keyGenerate;
@@ -0,0 +1,121 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const chalk = require("chalk");
4
+
5
+ function makeApiDocs(name) {
6
+ if (!name) {
7
+ console.log(chalk.red("❌ Please provide a apidocs name."));
8
+ return;
9
+ }
10
+
11
+ const fileName = `${name.toLowerCase()}-docs.ts`;
12
+ const targetDir = path.resolve("src", "apidocs");
13
+
14
+ if (!fs.existsSync(targetDir)) {
15
+ fs.mkdirSync(targetDir, { recursive: true });
16
+ }
17
+
18
+ const filePath = path.join(targetDir, fileName);
19
+ if (fs.existsSync(filePath)) {
20
+ console.log(chalk.yellow("⚠️ Apidocs already exists."));
21
+ return;
22
+ }
23
+
24
+ const content = `/**
25
+ * @swagger
26
+ * /api/${name}:
27
+ * get:
28
+ * summary: Mengambil daftar semua ${name}
29
+ * tags: [${name}s]
30
+ * security:
31
+ * - bearerAuth: []
32
+ * parameters:
33
+ * - in: query
34
+ * name: page
35
+ * schema:
36
+ * type: integer
37
+ * required: false
38
+ * description: Nomor halaman
39
+ * - in: query
40
+ * name: take
41
+ * schema:
42
+ * type: integer
43
+ * required: false
44
+ * description: Jumlah data per halaman
45
+ * - in: query
46
+ * name: name
47
+ * schema:
48
+ * type: string
49
+ * required: false
50
+ * description: Filter berdasarkan nama (fullName)
51
+ * responses:
52
+ * 200:
53
+ * description: Berhasil Get All Data
54
+ * content:
55
+ * application/json:
56
+ * schema:
57
+ * type: object
58
+ * properties:
59
+ * status:
60
+ * type: boolean
61
+ * status_code:
62
+ * type: integer
63
+ * message:
64
+ * type: string
65
+ * data:
66
+ * type: object
67
+ * properties:
68
+ * data:
69
+ * type: array
70
+ * items:
71
+ * type: object
72
+ * properties:
73
+ * id:
74
+ * type: string
75
+ * format: uuid
76
+ * fullName:
77
+ * type: string
78
+ * email:
79
+ * type: string
80
+ * username:
81
+ * type: string
82
+ * password:
83
+ * type: string
84
+ * description: (Hashed password)
85
+ * image_id:
86
+ * type: string
87
+ * image_url:
88
+ * type: string
89
+ * format: uri
90
+ * is_verify:
91
+ * type: boolean
92
+ * created_at:
93
+ * type: string
94
+ * format: date-time
95
+ * updated_at:
96
+ * type: string
97
+ * format: date-time
98
+ * deleted_at:
99
+ * type: string
100
+ * format: date-time
101
+ * nullable: true
102
+ * role_id:
103
+ * type: string
104
+ * format: uuid
105
+ * total_data:
106
+ * type: integer
107
+ * paging:
108
+ * type: object
109
+ * properties:
110
+ * current_page:
111
+ * type: integer
112
+ * total_page:
113
+ * type: integer
114
+
115
+ */
116
+ `;
117
+
118
+ fs.writeFileSync(filePath, content);
119
+ console.log(chalk.green(`✅ Controller created at ${filePath}`));
120
+ }
121
+ module.exports = makeApiDocs;
@@ -0,0 +1,38 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const chalk = require("chalk");
4
+
5
+ function makeCommand(name) {
6
+ if (!name) {
7
+ console.log(chalk.red("❌ Please provide a command name."));
8
+ return;
9
+ }
10
+
11
+ const fileName = `${name.toLowerCase()}.js`;
12
+ const targetDir = path.resolve("craft", "commands");
13
+
14
+ if (!fs.existsSync(targetDir)) {
15
+ fs.mkdirSync(targetDir, { recursive: true });
16
+ }
17
+
18
+ const filePath = path.join(targetDir, fileName);
19
+ if (fs.existsSync(filePath)) {
20
+ console.log(chalk.yellow("⚠️ Command already exists."));
21
+ return;
22
+ }
23
+
24
+ const content = `const fs = require("fs");
25
+ const path = require("path");
26
+ const chalk = require("chalk");
27
+
28
+ function make${name}(name) {
29
+
30
+ }
31
+
32
+ module.exports = make${name};
33
+ `;
34
+
35
+ fs.writeFileSync(filePath, content);
36
+ console.log(chalk.green(`✅ Command created at ${filePath}`));
37
+ }
38
+ module.exports = makeCommand;
@@ -0,0 +1,39 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const chalk = require("chalk");
4
+
5
+ const toPascalCase = (str) =>
6
+ str.replace(/(^\w|-\w)/g, (m) => m.replace("-", "").toUpperCase());
7
+
8
+ function makeDto(name) {
9
+ if (!name) {
10
+ console.log(chalk.red("❌ Please provide a dto name."));
11
+ return;
12
+ }
13
+
14
+ const typeName = `${toPascalCase(name)}Request`;
15
+ const fileName = `${name.toLowerCase()}-dto.ts`;
16
+ const targetDir = path.resolve("src", "dtos");
17
+
18
+ if (!fs.existsSync(targetDir)) {
19
+ fs.mkdirSync(targetDir, { recursive: true });
20
+ }
21
+
22
+ const filePath = path.join(targetDir, fileName);
23
+ if (fs.existsSync(filePath)) {
24
+ console.log(chalk.yellow("⚠️ Dto already exists."));
25
+ return;
26
+ }
27
+
28
+ const content = `export type ${typeName} = {
29
+ field1: string;
30
+ field2?: string; // optional
31
+
32
+ };
33
+ `;
34
+
35
+ fs.writeFileSync(filePath, content);
36
+ console.log(chalk.green(`✅ Dto created at ${filePath}`));
37
+ }
38
+
39
+ module.exports = makeDto;