@forinda/kickjs-cli 2.0.1 → 2.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/bin.js +8 -0
- package/dist/cli.mjs +6550 -0
- package/dist/index.d.mts +302 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3627 -0
- package/dist/index.mjs.map +1 -0
- package/dist/typegen-DCnJdqP1.mjs +886 -0
- package/dist/typegen-DCnJdqP1.mjs.map +1 -0
- package/package.json +31 -13
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -1552
- package/dist/commands/add.d.ts +0 -5
- package/dist/commands/add.d.ts.map +0 -1
- package/dist/commands/custom.d.ts +0 -56
- package/dist/commands/custom.d.ts.map +0 -1
- package/dist/commands/generate.d.ts +0 -3
- package/dist/commands/generate.d.ts.map +0 -1
- package/dist/commands/info.d.ts +0 -3
- package/dist/commands/info.d.ts.map +0 -1
- package/dist/commands/init.d.ts +0 -3
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/inspect.d.ts +0 -3
- package/dist/commands/inspect.d.ts.map +0 -1
- package/dist/commands/remove.d.ts +0 -3
- package/dist/commands/remove.d.ts.map +0 -1
- package/dist/commands/run.d.ts +0 -3
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/tinker.d.ts +0 -3
- package/dist/commands/tinker.d.ts.map +0 -1
- package/dist/config-D9faxBLQ.js +0 -3108
- package/dist/config.d.ts +0 -131
- package/dist/config.d.ts.map +0 -1
- package/dist/generators/adapter.d.ts +0 -7
- package/dist/generators/adapter.d.ts.map +0 -1
- package/dist/generators/config.d.ts +0 -9
- package/dist/generators/config.d.ts.map +0 -1
- package/dist/generators/controller.d.ts +0 -11
- package/dist/generators/controller.d.ts.map +0 -1
- package/dist/generators/dto.d.ts +0 -11
- package/dist/generators/dto.d.ts.map +0 -1
- package/dist/generators/guard.d.ts +0 -11
- package/dist/generators/guard.d.ts.map +0 -1
- package/dist/generators/job.d.ts +0 -8
- package/dist/generators/job.d.ts.map +0 -1
- package/dist/generators/middleware.d.ts +0 -11
- package/dist/generators/middleware.d.ts.map +0 -1
- package/dist/generators/module.d.ts +0 -33
- package/dist/generators/module.d.ts.map +0 -1
- package/dist/generators/patterns/cqrs.d.ts +0 -3
- package/dist/generators/patterns/cqrs.d.ts.map +0 -1
- package/dist/generators/patterns/ddd.d.ts +0 -3
- package/dist/generators/patterns/ddd.d.ts.map +0 -1
- package/dist/generators/patterns/index.d.ts +0 -6
- package/dist/generators/patterns/index.d.ts.map +0 -1
- package/dist/generators/patterns/minimal.d.ts +0 -3
- package/dist/generators/patterns/minimal.d.ts.map +0 -1
- package/dist/generators/patterns/rest.d.ts +0 -3
- package/dist/generators/patterns/rest.d.ts.map +0 -1
- package/dist/generators/patterns/types.d.ts +0 -15
- package/dist/generators/patterns/types.d.ts.map +0 -1
- package/dist/generators/project.d.ts +0 -14
- package/dist/generators/project.d.ts.map +0 -1
- package/dist/generators/remove-module.d.ts +0 -12
- package/dist/generators/remove-module.d.ts.map +0 -1
- package/dist/generators/resolver.d.ts +0 -7
- package/dist/generators/resolver.d.ts.map +0 -1
- package/dist/generators/scaffold.d.ts +0 -20
- package/dist/generators/scaffold.d.ts.map +0 -1
- package/dist/generators/service.d.ts +0 -11
- package/dist/generators/service.d.ts.map +0 -1
- package/dist/generators/templates/constants.d.ts +0 -3
- package/dist/generators/templates/constants.d.ts.map +0 -1
- package/dist/generators/templates/controller.d.ts +0 -6
- package/dist/generators/templates/controller.d.ts.map +0 -1
- package/dist/generators/templates/cqrs.d.ts +0 -23
- package/dist/generators/templates/cqrs.d.ts.map +0 -1
- package/dist/generators/templates/domain.d.ts +0 -5
- package/dist/generators/templates/domain.d.ts.map +0 -1
- package/dist/generators/templates/drizzle/index.d.ts +0 -4
- package/dist/generators/templates/drizzle/index.d.ts.map +0 -1
- package/dist/generators/templates/dtos.d.ts +0 -5
- package/dist/generators/templates/dtos.d.ts.map +0 -1
- package/dist/generators/templates/index.d.ts +0 -14
- package/dist/generators/templates/index.d.ts.map +0 -1
- package/dist/generators/templates/module-index.d.ts +0 -13
- package/dist/generators/templates/module-index.d.ts.map +0 -1
- package/dist/generators/templates/prisma/index.d.ts +0 -3
- package/dist/generators/templates/prisma/index.d.ts.map +0 -1
- package/dist/generators/templates/project-app.d.ts +0 -9
- package/dist/generators/templates/project-app.d.ts.map +0 -1
- package/dist/generators/templates/project-config.d.ts +0 -23
- package/dist/generators/templates/project-config.d.ts.map +0 -1
- package/dist/generators/templates/project-docs.d.ts +0 -9
- package/dist/generators/templates/project-docs.d.ts.map +0 -1
- package/dist/generators/templates/repository.d.ts +0 -5
- package/dist/generators/templates/repository.d.ts.map +0 -1
- package/dist/generators/templates/rest-service.d.ts +0 -6
- package/dist/generators/templates/rest-service.d.ts.map +0 -1
- package/dist/generators/templates/tests.d.ts +0 -4
- package/dist/generators/templates/tests.d.ts.map +0 -1
- package/dist/generators/templates/types.d.ts +0 -20
- package/dist/generators/templates/types.d.ts.map +0 -1
- package/dist/generators/templates/use-cases.d.ts +0 -6
- package/dist/generators/templates/use-cases.d.ts.map +0 -1
- package/dist/generators/test.d.ts +0 -9
- package/dist/generators/test.d.ts.map +0 -1
- package/dist/index.d.ts +0 -12
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -17
- package/dist/utils/fs.d.ts +0 -11
- package/dist/utils/fs.d.ts.map +0 -1
- package/dist/utils/naming.d.ts +0 -18
- package/dist/utils/naming.d.ts.map +0 -1
- package/dist/utils/resolve-out-dir.d.ts +0 -25
- package/dist/utils/resolve-out-dir.d.ts.map +0 -1
- package/dist/utils/shell.d.ts +0 -3
- package/dist/utils/shell.d.ts.map +0 -1
package/dist/cli.js
DELETED
|
@@ -1,1552 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { _ as E, a as ee, b as P, c as te, d as oe, f as re, g as S, h as L, i as ne, l as ie, m as se, n as w, o as ae, p as _, r as R, s as ce, u as de, v as M, y as $ } from "./config-D9faxBLQ.js";
|
|
3
|
-
import { basename as pe, dirname as le, join as g, resolve as m } from "node:path";
|
|
4
|
-
import { createInterface as N } from "node:readline";
|
|
5
|
-
import { readFile as B, rm as me, writeFile as W } from "node:fs/promises";
|
|
6
|
-
import { execSync as q, fork as ue } from "node:child_process";
|
|
7
|
-
import { cpSync as fe, existsSync as j, mkdirSync as ge, readFileSync as $e, readdirSync as ye, rmSync as he } from "node:fs";
|
|
8
|
-
import { fileURLToPath as we, pathToFileURL as ke } from "node:url";
|
|
9
|
-
import { Command as ve } from "commander";
|
|
10
|
-
import { arch as De, platform as Re, release as xe } from "node:os";
|
|
11
|
-
function U(e, t) {
|
|
12
|
-
const r = N({
|
|
13
|
-
input: process.stdin,
|
|
14
|
-
output: process.stdout
|
|
15
|
-
}), o = t ? ` (${t})` : "";
|
|
16
|
-
return new Promise((n) => {
|
|
17
|
-
r.question(` ${e}${o}: `, (i) => {
|
|
18
|
-
r.close(), n(i.trim() || t || "");
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
async function A(e, t, r = 0) {
|
|
23
|
-
console.log(` ${e}`);
|
|
24
|
-
for (let n = 0; n < t.length; n++) console.log(` ${n === r ? ">" : " "} ${n + 1}. ${t[n]}`);
|
|
25
|
-
const o = await U("Choose", String(r + 1));
|
|
26
|
-
return t[parseInt(o, 10) - 1] ?? t[r];
|
|
27
|
-
}
|
|
28
|
-
async function z(e, t = !0) {
|
|
29
|
-
const r = await U(`${e} (${t ? "Y/n" : "y/N"})`);
|
|
30
|
-
return r ? r.toLowerCase().startsWith("y") : t;
|
|
31
|
-
}
|
|
32
|
-
function Ce(e) {
|
|
33
|
-
e.command("new [name]").alias("init").description('Create a new KickJS project (use "." for current directory)').option("-d, --directory <dir>", "Target directory (defaults to project name)").option("--pm <manager>", "Package manager: pnpm | npm | yarn").option("--git", "Initialize git repository").option("--no-git", "Skip git initialization").option("--install", "Install dependencies after scaffolding").option("--no-install", "Skip dependency installation").option("-f, --force", "Remove existing files without prompting").option("-t, --template <type>", "Project template: rest | graphql | ddd | cqrs | minimal").option("-r, --repo <type>", "Default repository: prisma | drizzle | inmemory | custom").action(async (t, r) => {
|
|
34
|
-
console.log(), t || (t = await U("Project name", "my-api"));
|
|
35
|
-
let o;
|
|
36
|
-
if (t === "." ? (o = m("."), t = pe(o)) : o = m(r.directory || t), j(o)) {
|
|
37
|
-
const d = ye(o);
|
|
38
|
-
if (d.length > 0) {
|
|
39
|
-
if (r.force) console.log(` Clearing existing files in ${o}...
|
|
40
|
-
`);
|
|
41
|
-
else {
|
|
42
|
-
console.log(` Directory "${t}" is not empty:`);
|
|
43
|
-
const p = d.slice(0, 5);
|
|
44
|
-
for (const l of p) console.log(` - ${l}`);
|
|
45
|
-
if (d.length > 5 && console.log(` ... and ${d.length - 5} more`), console.log(), !await z("Remove all existing files and proceed?", !1)) {
|
|
46
|
-
console.log(` Aborted.
|
|
47
|
-
`);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
for (const p of d) he(m(o, p), {
|
|
52
|
-
recursive: !0,
|
|
53
|
-
force: !0
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
let n = r.template;
|
|
58
|
-
n || (n = await A("Project template:", [
|
|
59
|
-
"REST API (Express + Swagger)",
|
|
60
|
-
"GraphQL API (GraphQL + GraphiQL)",
|
|
61
|
-
"DDD (Domain-Driven Design modules)",
|
|
62
|
-
"CQRS (Commands, Queries, Events + WS/Queue)",
|
|
63
|
-
"Minimal (bare Express)"
|
|
64
|
-
], 0), n = {
|
|
65
|
-
"REST API (Express + Swagger)": "rest",
|
|
66
|
-
"GraphQL API (GraphQL + GraphiQL)": "graphql",
|
|
67
|
-
"DDD (Domain-Driven Design modules)": "ddd",
|
|
68
|
-
"CQRS (Commands, Queries, Events + WS/Queue)": "cqrs",
|
|
69
|
-
"Minimal (bare Express)": "minimal"
|
|
70
|
-
}[n] ?? "rest");
|
|
71
|
-
let i = r.pm;
|
|
72
|
-
i || (i = await A("Package manager:", [
|
|
73
|
-
"pnpm",
|
|
74
|
-
"npm",
|
|
75
|
-
"yarn"
|
|
76
|
-
], 0));
|
|
77
|
-
let s = r.repo;
|
|
78
|
-
if (!s) {
|
|
79
|
-
const d = await A("Default repository/ORM:", [
|
|
80
|
-
"Prisma",
|
|
81
|
-
"Drizzle",
|
|
82
|
-
"In-Memory",
|
|
83
|
-
"Custom (specify later)"
|
|
84
|
-
], 0);
|
|
85
|
-
s = {
|
|
86
|
-
Prisma: "prisma",
|
|
87
|
-
Drizzle: "drizzle",
|
|
88
|
-
"In-Memory": "inmemory",
|
|
89
|
-
"Custom (specify later)": "custom"
|
|
90
|
-
}[d] ?? "inmemory", s === "custom" && (s = await U("Custom repository name", "custom"));
|
|
91
|
-
}
|
|
92
|
-
let a;
|
|
93
|
-
r.git === void 0 ? a = await z("Initialize git repository?", !0) : a = r.git;
|
|
94
|
-
let c;
|
|
95
|
-
r.install === void 0 ? c = await z("Install dependencies?", !0) : c = r.install, await ne({
|
|
96
|
-
name: t,
|
|
97
|
-
directory: o,
|
|
98
|
-
packageManager: i,
|
|
99
|
-
initGit: a,
|
|
100
|
-
installDeps: c,
|
|
101
|
-
template: n,
|
|
102
|
-
defaultRepo: s
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
async function je(e) {
|
|
107
|
-
const t = N({
|
|
108
|
-
input: process.stdin,
|
|
109
|
-
output: process.stdout
|
|
110
|
-
});
|
|
111
|
-
return new Promise((r) => {
|
|
112
|
-
t.question(` ${e} (y/N) `, (o) => {
|
|
113
|
-
t.close(), r(o.trim().toLowerCase() === "y");
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
async function Se(e) {
|
|
118
|
-
const t = g(e.outDir, "kick.config.ts"), r = e.modulesDir ?? "src/modules", o = e.defaultRepo ?? "inmemory";
|
|
119
|
-
return j(t) && !e.force && !await je("kick.config.ts already exists. Overwrite?") ? (console.log(`
|
|
120
|
-
Skipped — existing kick.config.ts preserved.`), []) : (await P(t, `import { defineConfig } from '@forinda/kickjs-cli'
|
|
121
|
-
|
|
122
|
-
export default defineConfig({
|
|
123
|
-
modulesDir: '${r}',
|
|
124
|
-
defaultRepo: '${o}',
|
|
125
|
-
|
|
126
|
-
commands: [
|
|
127
|
-
{
|
|
128
|
-
name: 'test',
|
|
129
|
-
description: 'Run tests with Vitest',
|
|
130
|
-
steps: 'npx vitest run',
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: 'format',
|
|
134
|
-
description: 'Format code with Prettier',
|
|
135
|
-
steps: 'npx prettier --write src/',
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: 'format:check',
|
|
139
|
-
description: 'Check formatting without writing',
|
|
140
|
-
steps: 'npx prettier --check src/',
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
name: 'check',
|
|
144
|
-
description: 'Run typecheck + format check',
|
|
145
|
-
steps: ['npx tsc --noEmit', 'npx prettier --check src/'],
|
|
146
|
-
aliases: ['verify', 'ci'],
|
|
147
|
-
},
|
|
148
|
-
],
|
|
149
|
-
})
|
|
150
|
-
`), [t]);
|
|
151
|
-
}
|
|
152
|
-
async function Pe(e) {
|
|
153
|
-
const { name: t, outDir: r } = e, o = E(t), n = S(t), i = L(t), s = [], a = async (c, d) => {
|
|
154
|
-
const p = g(r, c);
|
|
155
|
-
await P(p, d), s.push(p);
|
|
156
|
-
};
|
|
157
|
-
return await a(`${n}.resolver.ts`, `import { Service } from '@forinda/kickjs'
|
|
158
|
-
import { Resolver, Query, Mutation, Arg } from '@forinda/kickjs-graphql'
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* ${o} GraphQL Resolver
|
|
162
|
-
*
|
|
163
|
-
* Decorators:
|
|
164
|
-
* @Resolver(typeName?) — marks this class as a GraphQL resolver
|
|
165
|
-
* @Query(name?, { returnType?, description? }) — defines a query field
|
|
166
|
-
* @Mutation(name?, { returnType?, description? }) — defines a mutation field
|
|
167
|
-
* @Arg(name, type?) — marks a method parameter as a GraphQL argument
|
|
168
|
-
*/
|
|
169
|
-
@Service()
|
|
170
|
-
@Resolver('${o}')
|
|
171
|
-
export class ${o}Resolver {
|
|
172
|
-
private items: Array<{ id: string; name: string }> = []
|
|
173
|
-
|
|
174
|
-
@Query('${i}s', { returnType: '[${o}]', description: 'List all ${i}s' })
|
|
175
|
-
findAll() {
|
|
176
|
-
return this.items
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
@Query('${i}', { returnType: '${o}', description: 'Get a ${i} by ID' })
|
|
180
|
-
findById(@Arg('id', 'ID!') id: string) {
|
|
181
|
-
return this.items.find((item) => item.id === id) ?? null
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
@Mutation('create${o}', { returnType: '${o}', description: 'Create a new ${i}' })
|
|
185
|
-
create(@Arg('name', 'String!') name: string) {
|
|
186
|
-
const item = { id: String(this.items.length + 1), name }
|
|
187
|
-
this.items.push(item)
|
|
188
|
-
return item
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
@Mutation('update${o}', { returnType: '${o}', description: 'Update a ${i}' })
|
|
192
|
-
update(@Arg('id', 'ID!') id: string, @Arg('name', 'String!') name: string) {
|
|
193
|
-
const item = this.items.find((i) => i.id === id)
|
|
194
|
-
if (item) item.name = name
|
|
195
|
-
return item
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
@Mutation('delete${o}', { returnType: 'Boolean', description: 'Delete a ${i}' })
|
|
199
|
-
remove(@Arg('id', 'ID!') id: string) {
|
|
200
|
-
const idx = this.items.findIndex((i) => i.id === id)
|
|
201
|
-
if (idx === -1) return false
|
|
202
|
-
this.items.splice(idx, 1)
|
|
203
|
-
return true
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
`), await a(`${n}.typedefs.ts`, `/**
|
|
207
|
-
* ${o} GraphQL type definitions.
|
|
208
|
-
* Pass to GraphQLAdapter's typeDefs option to register custom types.
|
|
209
|
-
*/
|
|
210
|
-
export const ${i}TypeDefs = \`
|
|
211
|
-
type ${o} {
|
|
212
|
-
id: ID!
|
|
213
|
-
name: String!
|
|
214
|
-
}
|
|
215
|
-
\`
|
|
216
|
-
`), s;
|
|
217
|
-
}
|
|
218
|
-
async function Ie(e) {
|
|
219
|
-
const { name: t, outDir: r } = e, o = E(t), n = S(t), i = L(t), s = e.queue ?? `${n}-queue`, a = [];
|
|
220
|
-
return await (async (d, p) => {
|
|
221
|
-
const l = g(r, d);
|
|
222
|
-
await P(l, p), a.push(l);
|
|
223
|
-
})(`${n}.job.ts`, `import { Inject } from '@forinda/kickjs'
|
|
224
|
-
import { Job, Process, QUEUE_MANAGER, type QueueService } from '@forinda/kickjs-queue'
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* ${o} Job Processor
|
|
228
|
-
*
|
|
229
|
-
* Decorators:
|
|
230
|
-
* @Job(queueName) — marks this class as a job processor for a queue
|
|
231
|
-
* @Process(jobName?) — marks a method as the handler for a specific job type
|
|
232
|
-
* - Without a name: handles all jobs in the queue
|
|
233
|
-
* - With a name: handles only jobs matching that name
|
|
234
|
-
*
|
|
235
|
-
* To add jobs to this queue from a service or controller:
|
|
236
|
-
* @Inject(QUEUE_MANAGER) private queue: QueueService
|
|
237
|
-
* await this.queue.add('${s}', '${i}', { ... })
|
|
238
|
-
*/
|
|
239
|
-
@Job('${s}')
|
|
240
|
-
export class ${o}Job {
|
|
241
|
-
@Process()
|
|
242
|
-
async handle(job: { name: string; data: any; id?: string }) {
|
|
243
|
-
console.log(\`Processing \${job.name} (id: \${job.id})\`, job.data)
|
|
244
|
-
|
|
245
|
-
// TODO: Implement job logic here
|
|
246
|
-
// Example:
|
|
247
|
-
// await this.emailService.send(job.data.to, job.data.subject, job.data.body)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
@Process('${i}.priority')
|
|
251
|
-
async handlePriority(job: { name: string; data: any; id?: string }) {
|
|
252
|
-
console.log(\`Priority job: \${job.name}\`, job.data)
|
|
253
|
-
// Handle high-priority variant of this job
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
`), a;
|
|
257
|
-
}
|
|
258
|
-
var F = {
|
|
259
|
-
string: {
|
|
260
|
-
ts: "string",
|
|
261
|
-
zod: "z.string()"
|
|
262
|
-
},
|
|
263
|
-
text: {
|
|
264
|
-
ts: "string",
|
|
265
|
-
zod: "z.string()"
|
|
266
|
-
},
|
|
267
|
-
number: {
|
|
268
|
-
ts: "number",
|
|
269
|
-
zod: "z.number()"
|
|
270
|
-
},
|
|
271
|
-
int: {
|
|
272
|
-
ts: "number",
|
|
273
|
-
zod: "z.number().int()"
|
|
274
|
-
},
|
|
275
|
-
float: {
|
|
276
|
-
ts: "number",
|
|
277
|
-
zod: "z.number()"
|
|
278
|
-
},
|
|
279
|
-
boolean: {
|
|
280
|
-
ts: "boolean",
|
|
281
|
-
zod: "z.boolean()"
|
|
282
|
-
},
|
|
283
|
-
date: {
|
|
284
|
-
ts: "string",
|
|
285
|
-
zod: "z.string().datetime()"
|
|
286
|
-
},
|
|
287
|
-
email: {
|
|
288
|
-
ts: "string",
|
|
289
|
-
zod: "z.string().email()"
|
|
290
|
-
},
|
|
291
|
-
url: {
|
|
292
|
-
ts: "string",
|
|
293
|
-
zod: "z.string().url()"
|
|
294
|
-
},
|
|
295
|
-
uuid: {
|
|
296
|
-
ts: "string",
|
|
297
|
-
zod: "z.string().uuid()"
|
|
298
|
-
},
|
|
299
|
-
json: {
|
|
300
|
-
ts: "any",
|
|
301
|
-
zod: "z.any()"
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
function Oe(e) {
|
|
305
|
-
return e.map((t) => {
|
|
306
|
-
const r = t.indexOf(":");
|
|
307
|
-
if (r === -1) throw new Error(`Invalid field: "${t}". Use format: name:type (e.g. title:string)`);
|
|
308
|
-
const o = t.slice(0, r), n = t.slice(r + 1);
|
|
309
|
-
if (!o || !n) throw new Error(`Invalid field: "${t}". Use format: name:type (e.g. title:string)`);
|
|
310
|
-
const i = n.endsWith("?"), s = i ? n.slice(0, -1) : n;
|
|
311
|
-
if (s.startsWith("enum:")) {
|
|
312
|
-
const c = s.slice(5).split(",");
|
|
313
|
-
return {
|
|
314
|
-
name: o,
|
|
315
|
-
type: "enum",
|
|
316
|
-
tsType: c.map((d) => `'${d}'`).join(" | "),
|
|
317
|
-
zodType: `z.enum([${c.map((d) => `'${d}'`).join(", ")}])`,
|
|
318
|
-
optional: i
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
const a = F[s];
|
|
322
|
-
if (!a) {
|
|
323
|
-
const c = [...Object.keys(F), "enum:a,b,c"].join(", ");
|
|
324
|
-
throw new Error(`Unknown field type: "${s}". Valid types: ${c}`);
|
|
325
|
-
}
|
|
326
|
-
return {
|
|
327
|
-
name: o,
|
|
328
|
-
type: s,
|
|
329
|
-
tsType: a.ts,
|
|
330
|
-
zodType: a.zod,
|
|
331
|
-
optional: i
|
|
332
|
-
};
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
async function Te(e) {
|
|
336
|
-
const { name: t, fields: r, modulesDir: o, noEntity: n, noTests: i, repo: s = "inmemory" } = e, a = e.pluralize !== !1, c = S(t), d = E(t);
|
|
337
|
-
L(t);
|
|
338
|
-
const p = a ? _(c) : c, l = a ? se(d) : d, f = g(o, p), v = [], u = async (b, X) => {
|
|
339
|
-
const H = g(f, b);
|
|
340
|
-
await P(H, X), v.push(H);
|
|
341
|
-
};
|
|
342
|
-
await u("index.ts", Ge(d, c, p, s)), await u("constants.ts", Ae(d, r)), await u(`presentation/${c}.controller.ts`, Qe(d, c, p, l)), await u(`application/dtos/create-${c}.dto.ts`, Ee(d, r)), await u(`application/dtos/update-${c}.dto.ts`, be(d, r)), await u(`application/dtos/${c}-response.dto.ts`, Ue(d, r));
|
|
343
|
-
const I = Ne(d, c, p, l);
|
|
344
|
-
for (const b of I) await u(`application/use-cases/${b.file}`, b.content);
|
|
345
|
-
return await u(`domain/repositories/${c}.repository.ts`, Le(d, c)), await u(`domain/services/${c}-domain.service.ts`, _e(d, c)), s === "inmemory" && await u(`infrastructure/repositories/in-memory-${c}.repository.ts`, ze(d, c, r)), n || (await u(`domain/entities/${c}.entity.ts`, Me(d, c, r)), await u(`domain/value-objects/${c}-id.vo.ts`, qe(d))), await He(o, d, p), v;
|
|
346
|
-
}
|
|
347
|
-
function Ee(e, t) {
|
|
348
|
-
return `import { z } from 'zod'
|
|
349
|
-
|
|
350
|
-
export const create${e}Schema = z.object({
|
|
351
|
-
${t.map((r) => {
|
|
352
|
-
const o = r.zodType;
|
|
353
|
-
return ` ${r.name}: ${o}${r.optional ? ".optional()" : ""},`;
|
|
354
|
-
}).join(`
|
|
355
|
-
`)}
|
|
356
|
-
})
|
|
357
|
-
|
|
358
|
-
export type Create${e}DTO = z.infer<typeof create${e}Schema>
|
|
359
|
-
`;
|
|
360
|
-
}
|
|
361
|
-
function be(e, t) {
|
|
362
|
-
return `import { z } from 'zod'
|
|
363
|
-
|
|
364
|
-
export const update${e}Schema = z.object({
|
|
365
|
-
${t.map((r) => ` ${r.name}: ${r.zodType}.optional(),`).join(`
|
|
366
|
-
`)}
|
|
367
|
-
})
|
|
368
|
-
|
|
369
|
-
export type Update${e}DTO = z.infer<typeof update${e}Schema>
|
|
370
|
-
`;
|
|
371
|
-
}
|
|
372
|
-
function Ue(e, t) {
|
|
373
|
-
return `export interface ${e}ResponseDTO {
|
|
374
|
-
id: string
|
|
375
|
-
${t.map((r) => ` ${r.name}${r.optional ? "?" : ""}: ${r.tsType}`).join(`
|
|
376
|
-
`)}
|
|
377
|
-
createdAt: string
|
|
378
|
-
updatedAt: string
|
|
379
|
-
}
|
|
380
|
-
`;
|
|
381
|
-
}
|
|
382
|
-
function Ae(e, t) {
|
|
383
|
-
const r = t.filter((a) => a.tsType === "string").map((a) => `'${a.name}'`);
|
|
384
|
-
t.filter((a) => a.tsType === "number").map((a) => `'${a.name}'`);
|
|
385
|
-
const o = t.map((a) => `'${a.name}'`), n = [...o].join(", "), i = [
|
|
386
|
-
...o,
|
|
387
|
-
"'createdAt'",
|
|
388
|
-
"'updatedAt'"
|
|
389
|
-
].join(", "), s = r.length > 0 ? r.join(", ") : "'name'";
|
|
390
|
-
return `import type { ApiQueryParamsConfig } from '@forinda/kickjs'
|
|
391
|
-
|
|
392
|
-
export const ${e.toUpperCase()}_QUERY_CONFIG: ApiQueryParamsConfig = {
|
|
393
|
-
filterable: [${n}],
|
|
394
|
-
sortable: [${i}],
|
|
395
|
-
searchable: [${s}],
|
|
396
|
-
}
|
|
397
|
-
`;
|
|
398
|
-
}
|
|
399
|
-
function ze(e, t, r) {
|
|
400
|
-
return `import { randomUUID } from 'node:crypto'
|
|
401
|
-
import { Repository, HttpException } from '@forinda/kickjs'
|
|
402
|
-
import type { ParsedQuery } from '@forinda/kickjs'
|
|
403
|
-
import type { I${e}Repository } from '../../domain/repositories/${t}.repository'
|
|
404
|
-
import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
|
|
405
|
-
import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
|
|
406
|
-
import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
|
|
407
|
-
|
|
408
|
-
@Repository()
|
|
409
|
-
export class InMemory${e}Repository implements I${e}Repository {
|
|
410
|
-
private store = new Map<string, ${e}ResponseDTO>()
|
|
411
|
-
|
|
412
|
-
async findById(id: string): Promise<${e}ResponseDTO | null> {
|
|
413
|
-
return this.store.get(id) ?? null
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
async findAll(): Promise<${e}ResponseDTO[]> {
|
|
417
|
-
return Array.from(this.store.values())
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
async findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }> {
|
|
421
|
-
const all = Array.from(this.store.values())
|
|
422
|
-
const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)
|
|
423
|
-
return { data, total: all.length }
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
async create(dto: Create${e}DTO): Promise<${e}ResponseDTO> {
|
|
427
|
-
const now = new Date().toISOString()
|
|
428
|
-
const entity: ${e}ResponseDTO = {
|
|
429
|
-
id: randomUUID(),
|
|
430
|
-
${r.map((o) => ` ${o.name}: dto.${o.name},`).join(`
|
|
431
|
-
`)}
|
|
432
|
-
createdAt: now,
|
|
433
|
-
updatedAt: now,
|
|
434
|
-
}
|
|
435
|
-
this.store.set(entity.id, entity)
|
|
436
|
-
return entity
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
async update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO> {
|
|
440
|
-
const existing = this.store.get(id)
|
|
441
|
-
if (!existing) throw HttpException.notFound('${e} not found')
|
|
442
|
-
const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }
|
|
443
|
-
this.store.set(id, updated)
|
|
444
|
-
return updated
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
async delete(id: string): Promise<void> {
|
|
448
|
-
if (!this.store.has(id)) throw HttpException.notFound('${e} not found')
|
|
449
|
-
this.store.delete(id)
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
`;
|
|
453
|
-
}
|
|
454
|
-
function Me(e, t, r) {
|
|
455
|
-
return `import { ${e}Id } from '../value-objects/${t}-id.vo'
|
|
456
|
-
|
|
457
|
-
interface ${e}Props {
|
|
458
|
-
id: ${e}Id
|
|
459
|
-
${r.map((o) => ` ${o.name}${o.optional ? "?" : ""}: ${o.tsType}`).join(`
|
|
460
|
-
`)}
|
|
461
|
-
createdAt: Date
|
|
462
|
-
updatedAt: Date
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
export class ${e} {
|
|
466
|
-
private constructor(private props: ${e}Props) {}
|
|
467
|
-
|
|
468
|
-
static create(params: { ${r.filter((o) => !o.optional).map((o) => `${o.name}: ${o.tsType}`).join("; ")} }): ${e} {
|
|
469
|
-
const now = new Date()
|
|
470
|
-
return new ${e}({
|
|
471
|
-
id: ${e}Id.create(),
|
|
472
|
-
${r.filter((o) => !o.optional).map((o) => ` ${o.name}: params.${o.name},`).join(`
|
|
473
|
-
`)}
|
|
474
|
-
createdAt: now,
|
|
475
|
-
updatedAt: now,
|
|
476
|
-
})
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
static reconstitute(props: ${e}Props): ${e} {
|
|
480
|
-
return new ${e}(props)
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
get id(): ${e}Id { return this.props.id }
|
|
484
|
-
${r.map((o) => ` get ${o.name}(): ${o.tsType}${o.optional ? " | undefined" : ""} {
|
|
485
|
-
return this.props.${o.name}
|
|
486
|
-
}`).join(`
|
|
487
|
-
`)}
|
|
488
|
-
get createdAt(): Date { return this.props.createdAt }
|
|
489
|
-
get updatedAt(): Date { return this.props.updatedAt }
|
|
490
|
-
|
|
491
|
-
toJSON() {
|
|
492
|
-
return {
|
|
493
|
-
id: this.props.id.toString(),
|
|
494
|
-
${r.map((o) => ` ${o.name}: this.props.${o.name},`).join(`
|
|
495
|
-
`)}
|
|
496
|
-
createdAt: this.props.createdAt.toISOString(),
|
|
497
|
-
updatedAt: this.props.updatedAt.toISOString(),
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
`;
|
|
502
|
-
}
|
|
503
|
-
function qe(e) {
|
|
504
|
-
return `import { randomUUID } from 'node:crypto'
|
|
505
|
-
|
|
506
|
-
export class ${e}Id {
|
|
507
|
-
private constructor(private readonly value: string) {}
|
|
508
|
-
|
|
509
|
-
static create(): ${e}Id { return new ${e}Id(randomUUID()) }
|
|
510
|
-
|
|
511
|
-
static from(id: string): ${e}Id {
|
|
512
|
-
if (!id || id.trim().length === 0) throw new Error('${e}Id cannot be empty')
|
|
513
|
-
return new ${e}Id(id)
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
toString(): string { return this.value }
|
|
517
|
-
equals(other: ${e}Id): boolean { return this.value === other.value }
|
|
518
|
-
}
|
|
519
|
-
`;
|
|
520
|
-
}
|
|
521
|
-
function Ge(e, t, r, o) {
|
|
522
|
-
return `import type { AppModule, AppModuleClass } from '@forinda/kickjs'
|
|
523
|
-
import { ${e}Controller } from './presentation/${t}.controller'
|
|
524
|
-
import { ${e}DomainService } from './domain/services/${t}-domain.service'
|
|
525
|
-
import { ${e.toUpperCase()}_REPOSITORY } from './domain/repositories/${t}.repository'
|
|
526
|
-
import { InMemory${e}Repository } from './infrastructure/repositories/in-memory-${t}.repository'
|
|
527
|
-
|
|
528
|
-
export class ${e}Module implements AppModule {
|
|
529
|
-
register(container: any): void {
|
|
530
|
-
container.registerFactory(
|
|
531
|
-
${e.toUpperCase()}_REPOSITORY,
|
|
532
|
-
() => container.resolve(InMemory${e}Repository),
|
|
533
|
-
)
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
routes() {
|
|
537
|
-
return { prefix: '/${r}', controllers: [${e}Controller] }
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
`;
|
|
541
|
-
}
|
|
542
|
-
function Qe(e, t, r, o) {
|
|
543
|
-
return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs'
|
|
544
|
-
import type { RequestContext } from '@forinda/kickjs'
|
|
545
|
-
import { ApiTags } from '@forinda/kickjs-swagger'
|
|
546
|
-
import { Create${e}UseCase } from '../application/use-cases/create-${t}.use-case'
|
|
547
|
-
import { Get${e}UseCase } from '../application/use-cases/get-${t}.use-case'
|
|
548
|
-
import { List${o}UseCase } from '../application/use-cases/list-${r}.use-case'
|
|
549
|
-
import { Update${e}UseCase } from '../application/use-cases/update-${t}.use-case'
|
|
550
|
-
import { Delete${e}UseCase } from '../application/use-cases/delete-${t}.use-case'
|
|
551
|
-
import { create${e}Schema } from '../application/dtos/create-${t}.dto'
|
|
552
|
-
import { update${e}Schema } from '../application/dtos/update-${t}.dto'
|
|
553
|
-
import { ${e.toUpperCase()}_QUERY_CONFIG } from '../constants'
|
|
554
|
-
|
|
555
|
-
@Controller()
|
|
556
|
-
export class ${e}Controller {
|
|
557
|
-
@Autowired() private create${e}UseCase!: Create${e}UseCase
|
|
558
|
-
@Autowired() private get${e}UseCase!: Get${e}UseCase
|
|
559
|
-
@Autowired() private list${o}UseCase!: List${o}UseCase
|
|
560
|
-
@Autowired() private update${e}UseCase!: Update${e}UseCase
|
|
561
|
-
@Autowired() private delete${e}UseCase!: Delete${e}UseCase
|
|
562
|
-
|
|
563
|
-
@Get('/')
|
|
564
|
-
@ApiTags('${e}')
|
|
565
|
-
@ApiQueryParams(${e.toUpperCase()}_QUERY_CONFIG)
|
|
566
|
-
async list(ctx: RequestContext) {
|
|
567
|
-
return ctx.paginate(
|
|
568
|
-
(parsed) => this.list${o}UseCase.execute(parsed),
|
|
569
|
-
${e.toUpperCase()}_QUERY_CONFIG,
|
|
570
|
-
)
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
@Get('/:id')
|
|
574
|
-
@ApiTags('${e}')
|
|
575
|
-
async getById(ctx: RequestContext) {
|
|
576
|
-
const result = await this.get${e}UseCase.execute(ctx.params.id)
|
|
577
|
-
if (!result) return ctx.notFound('${e} not found')
|
|
578
|
-
ctx.json(result)
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
@Post('/', { body: create${e}Schema, name: 'Create${e}' })
|
|
582
|
-
@ApiTags('${e}')
|
|
583
|
-
async create(ctx: RequestContext) {
|
|
584
|
-
const result = await this.create${e}UseCase.execute(ctx.body)
|
|
585
|
-
ctx.created(result)
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
@Put('/:id', { body: update${e}Schema, name: 'Update${e}' })
|
|
589
|
-
@ApiTags('${e}')
|
|
590
|
-
async update(ctx: RequestContext) {
|
|
591
|
-
const result = await this.update${e}UseCase.execute(ctx.params.id, ctx.body)
|
|
592
|
-
ctx.json(result)
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
@Delete('/:id')
|
|
596
|
-
@ApiTags('${e}')
|
|
597
|
-
async remove(ctx: RequestContext) {
|
|
598
|
-
await this.delete${e}UseCase.execute(ctx.params.id)
|
|
599
|
-
ctx.noContent()
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
`;
|
|
603
|
-
}
|
|
604
|
-
function Le(e, t) {
|
|
605
|
-
return `import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
|
|
606
|
-
import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
|
|
607
|
-
import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
|
|
608
|
-
import type { ParsedQuery } from '@forinda/kickjs'
|
|
609
|
-
|
|
610
|
-
export interface I${e}Repository {
|
|
611
|
-
findById(id: string): Promise<${e}ResponseDTO | null>
|
|
612
|
-
findAll(): Promise<${e}ResponseDTO[]>
|
|
613
|
-
findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }>
|
|
614
|
-
create(dto: Create${e}DTO): Promise<${e}ResponseDTO>
|
|
615
|
-
update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO>
|
|
616
|
-
delete(id: string): Promise<void>
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
export const ${e.toUpperCase()}_REPOSITORY = Symbol('I${e}Repository')
|
|
620
|
-
`;
|
|
621
|
-
}
|
|
622
|
-
function _e(e, t) {
|
|
623
|
-
return `import { Service, Inject, HttpException } from '@forinda/kickjs'
|
|
624
|
-
import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../repositories/${t}.repository'
|
|
625
|
-
|
|
626
|
-
@Service()
|
|
627
|
-
export class ${e}DomainService {
|
|
628
|
-
constructor(
|
|
629
|
-
@Inject(${e.toUpperCase()}_REPOSITORY) private readonly repo: I${e}Repository,
|
|
630
|
-
) {}
|
|
631
|
-
|
|
632
|
-
async ensureExists(id: string): Promise<void> {
|
|
633
|
-
const entity = await this.repo.findById(id)
|
|
634
|
-
if (!entity) throw HttpException.notFound('${e} not found')
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
`;
|
|
638
|
-
}
|
|
639
|
-
function Ne(e, t, r, o) {
|
|
640
|
-
return [
|
|
641
|
-
{
|
|
642
|
-
file: `create-${t}.use-case.ts`,
|
|
643
|
-
content: `import { Service, Inject } from '@forinda/kickjs'
|
|
644
|
-
import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
|
|
645
|
-
import type { Create${e}DTO } from '../dtos/create-${t}.dto'
|
|
646
|
-
|
|
647
|
-
@Service()
|
|
648
|
-
export class Create${e}UseCase {
|
|
649
|
-
constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
|
|
650
|
-
async execute(dto: Create${e}DTO) { return this.repo.create(dto) }
|
|
651
|
-
}
|
|
652
|
-
`
|
|
653
|
-
},
|
|
654
|
-
{
|
|
655
|
-
file: `get-${t}.use-case.ts`,
|
|
656
|
-
content: `import { Service, Inject } from '@forinda/kickjs'
|
|
657
|
-
import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
|
|
658
|
-
|
|
659
|
-
@Service()
|
|
660
|
-
export class Get${e}UseCase {
|
|
661
|
-
constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
|
|
662
|
-
async execute(id: string) { return this.repo.findById(id) }
|
|
663
|
-
}
|
|
664
|
-
`
|
|
665
|
-
},
|
|
666
|
-
{
|
|
667
|
-
file: `list-${r}.use-case.ts`,
|
|
668
|
-
content: `import { Service, Inject } from '@forinda/kickjs'
|
|
669
|
-
import type { ParsedQuery } from '@forinda/kickjs'
|
|
670
|
-
import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
|
|
671
|
-
|
|
672
|
-
@Service()
|
|
673
|
-
export class List${o}UseCase {
|
|
674
|
-
constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
|
|
675
|
-
async execute(parsed: ParsedQuery) { return this.repo.findPaginated(parsed) }
|
|
676
|
-
}
|
|
677
|
-
`
|
|
678
|
-
},
|
|
679
|
-
{
|
|
680
|
-
file: `update-${t}.use-case.ts`,
|
|
681
|
-
content: `import { Service, Inject } from '@forinda/kickjs'
|
|
682
|
-
import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
|
|
683
|
-
import type { Update${e}DTO } from '../dtos/update-${t}.dto'
|
|
684
|
-
|
|
685
|
-
@Service()
|
|
686
|
-
export class Update${e}UseCase {
|
|
687
|
-
constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
|
|
688
|
-
async execute(id: string, dto: Update${e}DTO) { return this.repo.update(id, dto) }
|
|
689
|
-
}
|
|
690
|
-
`
|
|
691
|
-
},
|
|
692
|
-
{
|
|
693
|
-
file: `delete-${t}.use-case.ts`,
|
|
694
|
-
content: `import { Service, Inject } from '@forinda/kickjs'
|
|
695
|
-
import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
|
|
696
|
-
|
|
697
|
-
@Service()
|
|
698
|
-
export class Delete${e}UseCase {
|
|
699
|
-
constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
|
|
700
|
-
async execute(id: string) { return this.repo.delete(id) }
|
|
701
|
-
}
|
|
702
|
-
`
|
|
703
|
-
}
|
|
704
|
-
];
|
|
705
|
-
}
|
|
706
|
-
async function He(e, t, r) {
|
|
707
|
-
const o = g(e, "index.ts");
|
|
708
|
-
if (!await M(o)) {
|
|
709
|
-
await P(o, `import type { AppModuleClass } from '@forinda/kickjs'
|
|
710
|
-
import { ${t}Module } from './${r}'
|
|
711
|
-
|
|
712
|
-
export const modules: AppModuleClass[] = [${t}Module]
|
|
713
|
-
`);
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
716
|
-
let n = await B(o, "utf-8");
|
|
717
|
-
const i = `import { ${t}Module } from './${r}'`;
|
|
718
|
-
if (!n.includes(`${t}Module`)) {
|
|
719
|
-
const s = n.lastIndexOf("import ");
|
|
720
|
-
if (s !== -1) {
|
|
721
|
-
const a = n.indexOf(`
|
|
722
|
-
`, s);
|
|
723
|
-
n = n.slice(0, a + 1) + i + `
|
|
724
|
-
` + n.slice(a + 1);
|
|
725
|
-
} else n = i + `
|
|
726
|
-
` + n;
|
|
727
|
-
n = n.replace(/(=\s*\[)([\s\S]*?)(])/, (a, c, d, p) => {
|
|
728
|
-
const l = d.trim();
|
|
729
|
-
if (!l) return `${c}${t}Module${p}`;
|
|
730
|
-
const f = l.endsWith(",") ? "" : ",";
|
|
731
|
-
return `${c}${d.trimEnd()}${f} ${t}Module${p}`;
|
|
732
|
-
});
|
|
733
|
-
}
|
|
734
|
-
await W(o, n, "utf-8");
|
|
735
|
-
}
|
|
736
|
-
async function Fe(e) {
|
|
737
|
-
const { name: t, moduleName: r, modulesDir: o } = e, n = S(t), i = E(t), s = [];
|
|
738
|
-
let a;
|
|
739
|
-
if (e.outDir) a = m(e.outDir);
|
|
740
|
-
else if (r) {
|
|
741
|
-
const d = _(S(r));
|
|
742
|
-
a = m(g(o ?? "src/modules", d, "__tests__"));
|
|
743
|
-
} else a = m("src/__tests__");
|
|
744
|
-
const c = g(a, `${n}.test.ts`);
|
|
745
|
-
return await P(c, `import { describe, it, expect, beforeEach } from 'vitest'
|
|
746
|
-
import { Container } from '@forinda/kickjs'
|
|
747
|
-
|
|
748
|
-
describe('${i}', () => {
|
|
749
|
-
beforeEach(() => {
|
|
750
|
-
Container.reset()
|
|
751
|
-
})
|
|
752
|
-
|
|
753
|
-
it('should be defined', () => {
|
|
754
|
-
// TODO: Import and test your class/function here
|
|
755
|
-
expect(true).toBe(true)
|
|
756
|
-
})
|
|
757
|
-
|
|
758
|
-
it('should handle the happy path', async () => {
|
|
759
|
-
// TODO: Set up test data and assertions
|
|
760
|
-
expect(true).toBe(true)
|
|
761
|
-
})
|
|
762
|
-
|
|
763
|
-
it('should handle edge cases', async () => {
|
|
764
|
-
// TODO: Test error handling, empty inputs, etc.
|
|
765
|
-
expect(true).toBe(true)
|
|
766
|
-
})
|
|
767
|
-
})
|
|
768
|
-
`), s.push(c), s;
|
|
769
|
-
}
|
|
770
|
-
function y(e) {
|
|
771
|
-
return e.parent?.opts()?.dryRun ?? !1;
|
|
772
|
-
}
|
|
773
|
-
function h(e, t = !1) {
|
|
774
|
-
const r = process.cwd();
|
|
775
|
-
console.log(`
|
|
776
|
-
${t ? "Would generate" : "Generated"} ${e.length} file${e.length === 1 ? "" : "s"}:`);
|
|
777
|
-
for (const o of e) console.log(` ${o.replace(r + "/", "")}`);
|
|
778
|
-
t && console.log(`
|
|
779
|
-
(dry run — no files were written)`), console.log();
|
|
780
|
-
}
|
|
781
|
-
var J = [
|
|
782
|
-
{
|
|
783
|
-
name: "module <name>",
|
|
784
|
-
description: "Full DDD module (controller, DTOs, use-cases, repo)"
|
|
785
|
-
},
|
|
786
|
-
{
|
|
787
|
-
name: "scaffold <name> <fields...>",
|
|
788
|
-
description: "CRUD module from field definitions"
|
|
789
|
-
},
|
|
790
|
-
{
|
|
791
|
-
name: "controller <name>",
|
|
792
|
-
description: "@Controller() class [-m module]"
|
|
793
|
-
},
|
|
794
|
-
{
|
|
795
|
-
name: "service <name>",
|
|
796
|
-
description: "@Service() singleton [-m module]"
|
|
797
|
-
},
|
|
798
|
-
{
|
|
799
|
-
name: "middleware <name>",
|
|
800
|
-
description: "Express middleware function [-m module]"
|
|
801
|
-
},
|
|
802
|
-
{
|
|
803
|
-
name: "guard <name>",
|
|
804
|
-
description: "Route guard (auth, roles, etc.) [-m module]"
|
|
805
|
-
},
|
|
806
|
-
{
|
|
807
|
-
name: "dto <name>",
|
|
808
|
-
description: "Zod DTO schema [-m module]"
|
|
809
|
-
},
|
|
810
|
-
{
|
|
811
|
-
name: "adapter <name>",
|
|
812
|
-
description: "AppAdapter with lifecycle hooks (app-level only)"
|
|
813
|
-
},
|
|
814
|
-
{
|
|
815
|
-
name: "test <name>",
|
|
816
|
-
description: "Vitest test scaffold [-m module]"
|
|
817
|
-
},
|
|
818
|
-
{
|
|
819
|
-
name: "resolver <name>",
|
|
820
|
-
description: "GraphQL @Resolver class"
|
|
821
|
-
},
|
|
822
|
-
{
|
|
823
|
-
name: "job <name>",
|
|
824
|
-
description: "Queue @Job processor"
|
|
825
|
-
},
|
|
826
|
-
{
|
|
827
|
-
name: "config",
|
|
828
|
-
description: "Generate kick.config.ts"
|
|
829
|
-
}
|
|
830
|
-
];
|
|
831
|
-
function Je() {
|
|
832
|
-
console.log(`
|
|
833
|
-
Available generators:
|
|
834
|
-
`);
|
|
835
|
-
const e = Math.max(...J.map((t) => t.name.length));
|
|
836
|
-
for (const t of J) console.log(` kick g ${t.name.padEnd(e + 2)} ${t.description}`);
|
|
837
|
-
console.log();
|
|
838
|
-
}
|
|
839
|
-
function Ye(e) {
|
|
840
|
-
const t = e.command("generate").alias("g").description("Generate code scaffolds").option("--list", "List all available generators").option("--dry-run", "Preview files that would be generated without writing them").action((r) => {
|
|
841
|
-
r.list ? Je() : t.help();
|
|
842
|
-
});
|
|
843
|
-
t.command("module <names...>").description("Generate one or more modules (e.g. kick g module user task project)").option("--no-entity", "Skip entity and value object generation").option("--no-tests", "Skip test file generation").option("--repo <type>", "Repository implementation: inmemory | drizzle | prisma").option("--pattern <pattern>", "Override project pattern: rest | ddd | cqrs | minimal").option("--minimal", "Shorthand for --pattern minimal").option("--modules-dir <dir>", "Modules directory").option("--no-pluralize", "Use singular names (skip auto-pluralization)").option("-f, --force", "Overwrite existing files without prompting").action(async (r, o, n) => {
|
|
844
|
-
const i = y(n);
|
|
845
|
-
$(i);
|
|
846
|
-
const s = await w(process.cwd()), a = R(s), c = o.modulesDir ?? a.dir ?? "src/modules", d = o.repo ?? re(a.repo), p = o.pattern ?? s?.pattern ?? "ddd", l = o.pluralize === !1 ? !1 : a.pluralize ?? !0, f = [];
|
|
847
|
-
for (const v of r) {
|
|
848
|
-
const u = await oe({
|
|
849
|
-
name: v,
|
|
850
|
-
modulesDir: m(c),
|
|
851
|
-
noEntity: o.entity === !1,
|
|
852
|
-
noTests: o.tests === !1,
|
|
853
|
-
repo: d,
|
|
854
|
-
minimal: o.minimal,
|
|
855
|
-
force: o.force,
|
|
856
|
-
pattern: p,
|
|
857
|
-
dryRun: i,
|
|
858
|
-
pluralize: l,
|
|
859
|
-
prismaClientPath: a.prismaClientPath
|
|
860
|
-
});
|
|
861
|
-
f.push(...u);
|
|
862
|
-
}
|
|
863
|
-
h(f, i);
|
|
864
|
-
}), t.command("adapter <name>").description("Generate an AppAdapter with lifecycle hooks and middleware support").option("-o, --out <dir>", "Output directory", "src/adapters").action(async (r, o, n) => {
|
|
865
|
-
const i = y(n);
|
|
866
|
-
$(i), h(await de({
|
|
867
|
-
name: r,
|
|
868
|
-
outDir: m(o.out)
|
|
869
|
-
}), i);
|
|
870
|
-
}), t.command("middleware <name>").description(`Generate an Express middleware function
|
|
871
|
-
Use -m to scope it to a module: kick g middleware auth -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
|
|
872
|
-
const i = y(n);
|
|
873
|
-
$(i);
|
|
874
|
-
const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
|
|
875
|
-
h(await ie({
|
|
876
|
-
name: r,
|
|
877
|
-
outDir: o.out,
|
|
878
|
-
moduleName: o.module,
|
|
879
|
-
modulesDir: a,
|
|
880
|
-
pattern: s?.pattern
|
|
881
|
-
}), i);
|
|
882
|
-
}), t.command("guard <name>").description(`Generate a route guard (auth, roles, etc.)
|
|
883
|
-
Use -m to scope it to a module: kick g guard admin -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
|
|
884
|
-
const i = y(n);
|
|
885
|
-
$(i);
|
|
886
|
-
const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
|
|
887
|
-
h(await te({
|
|
888
|
-
name: r,
|
|
889
|
-
outDir: o.out,
|
|
890
|
-
moduleName: o.module,
|
|
891
|
-
modulesDir: a,
|
|
892
|
-
pattern: s?.pattern
|
|
893
|
-
}), i);
|
|
894
|
-
}), t.command("service <name>").description(`Generate a @Service() class
|
|
895
|
-
Use -m to scope it to a module: kick g service payment -m orders`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
|
|
896
|
-
const i = y(n);
|
|
897
|
-
$(i);
|
|
898
|
-
const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
|
|
899
|
-
h(await ce({
|
|
900
|
-
name: r,
|
|
901
|
-
outDir: o.out,
|
|
902
|
-
moduleName: o.module,
|
|
903
|
-
modulesDir: a,
|
|
904
|
-
pattern: s?.pattern
|
|
905
|
-
}), i);
|
|
906
|
-
}), t.command("controller <name>").description(`Generate a @Controller() class with basic routes
|
|
907
|
-
Use -m to scope it to a module: kick g controller auth -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
|
|
908
|
-
const i = y(n);
|
|
909
|
-
$(i);
|
|
910
|
-
const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
|
|
911
|
-
h(await ae({
|
|
912
|
-
name: r,
|
|
913
|
-
outDir: o.out,
|
|
914
|
-
moduleName: o.module,
|
|
915
|
-
modulesDir: a,
|
|
916
|
-
pattern: s?.pattern
|
|
917
|
-
}), i);
|
|
918
|
-
}), t.command("dto <name>").description(`Generate a Zod DTO schema
|
|
919
|
-
Use -m to scope it to a module: kick g dto create-user -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
|
|
920
|
-
const i = y(n);
|
|
921
|
-
$(i);
|
|
922
|
-
const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
|
|
923
|
-
h(await ee({
|
|
924
|
-
name: r,
|
|
925
|
-
outDir: o.out,
|
|
926
|
-
moduleName: o.module,
|
|
927
|
-
modulesDir: a,
|
|
928
|
-
pattern: s?.pattern
|
|
929
|
-
}), i);
|
|
930
|
-
}), t.command("test <name>").description(`Generate a Vitest test scaffold
|
|
931
|
-
Use -m to scope it to a module: kick g test user-service -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module's __tests__/ folder").action(async (r, o, n) => {
|
|
932
|
-
const i = y(n);
|
|
933
|
-
$(i);
|
|
934
|
-
const s = R(await w(process.cwd())).dir ?? "src/modules";
|
|
935
|
-
h(await Fe({
|
|
936
|
-
name: r,
|
|
937
|
-
outDir: o.out,
|
|
938
|
-
moduleName: o.module,
|
|
939
|
-
modulesDir: s
|
|
940
|
-
}), i);
|
|
941
|
-
}), t.command("resolver <name>").description("Generate a GraphQL @Resolver class with @Query and @Mutation methods").option("-o, --out <dir>", "Output directory", "src/resolvers").action(async (r, o, n) => {
|
|
942
|
-
const i = y(n);
|
|
943
|
-
$(i), h(await Pe({
|
|
944
|
-
name: r,
|
|
945
|
-
outDir: m(o.out)
|
|
946
|
-
}), i);
|
|
947
|
-
}), t.command("job <name>").description("Generate a @Job queue processor with @Process handlers").option("-o, --out <dir>", "Output directory", "src/jobs").option("-q, --queue <name>", "Queue name (default: <name>-queue)").action(async (r, o, n) => {
|
|
948
|
-
const i = y(n);
|
|
949
|
-
$(i), h(await Ie({
|
|
950
|
-
name: r,
|
|
951
|
-
outDir: m(o.out),
|
|
952
|
-
queue: o.queue
|
|
953
|
-
}), i);
|
|
954
|
-
}), t.command("scaffold <name> [fields...]").description(`Generate a full CRUD module from field definitions
|
|
955
|
-
Example: kick g scaffold Post title:string body:text published:boolean?
|
|
956
|
-
Types: string, text, number, int, float, boolean, date, email, url, uuid, json, enum:a,b,c
|
|
957
|
-
Append ? for optional fields: description:text?`).option("--no-entity", "Skip entity and value object generation").option("--no-tests", "Skip test file generation").option("--no-pluralize", "Use singular names (skip auto-pluralization)").option("--modules-dir <dir>", "Modules directory").action(async (r, o, n, i) => {
|
|
958
|
-
const s = y(i);
|
|
959
|
-
$(s), o.length === 0 && (console.error(`
|
|
960
|
-
Error: At least one field is required.
|
|
961
|
-
Usage: kick g scaffold <name> <field:type> [field:type...]
|
|
962
|
-
Example: kick g scaffold Post title:string body:text published:boolean
|
|
963
|
-
`), process.exit(1));
|
|
964
|
-
const a = R(await w(process.cwd())), c = n.modulesDir ?? a.dir ?? "src/modules", d = Oe(o), p = await Te({
|
|
965
|
-
name: r,
|
|
966
|
-
fields: d,
|
|
967
|
-
modulesDir: m(c),
|
|
968
|
-
noEntity: n.entity === !1,
|
|
969
|
-
noTests: n.tests === !1,
|
|
970
|
-
pluralize: n.pluralize === !1 ? !1 : a.pluralize ?? !0
|
|
971
|
-
});
|
|
972
|
-
console.log(`
|
|
973
|
-
Scaffolded ${r} with ${d.length} field(s):`);
|
|
974
|
-
for (const l of d) console.log(` ${l.name}: ${l.type}${l.optional ? " (optional)" : ""}`);
|
|
975
|
-
h(p, s);
|
|
976
|
-
}), t.command("config").description("Generate a kick.config.ts at the project root").option("--modules-dir <dir>", "Modules directory path", "src/modules").option("--repo <type>", "Default repository type: inmemory | drizzle | prisma", "inmemory").option("-f, --force", "Overwrite existing kick.config.ts without prompting").action(async (r, o) => {
|
|
977
|
-
const n = y(o);
|
|
978
|
-
$(n), h(await Se({
|
|
979
|
-
outDir: m("."),
|
|
980
|
-
modulesDir: r.modulesDir,
|
|
981
|
-
defaultRepo: r.repo,
|
|
982
|
-
force: r.force
|
|
983
|
-
}), n);
|
|
984
|
-
});
|
|
985
|
-
}
|
|
986
|
-
function K(e, t) {
|
|
987
|
-
q(e, {
|
|
988
|
-
cwd: t,
|
|
989
|
-
stdio: "inherit"
|
|
990
|
-
});
|
|
991
|
-
}
|
|
992
|
-
async function Y(e, t) {
|
|
993
|
-
t && (process.env.PORT = t);
|
|
994
|
-
const { createRequire: r } = await import("node:module"), o = r(m("package.json")), n = o.resolve("vite"), { createServer: i, isRunnableDevEnvironment: s } = await import(n), a = await i({
|
|
995
|
-
configFile: m("vite.config.ts"),
|
|
996
|
-
appType: "custom",
|
|
997
|
-
server: {
|
|
998
|
-
middlewareMode: !0,
|
|
999
|
-
hmr: !0
|
|
1000
|
-
},
|
|
1001
|
-
environments: { ssr: {} },
|
|
1002
|
-
customLogger: (() => {
|
|
1003
|
-
const { createLogger: l } = o(n), f = l(), v = f.warn.bind(f);
|
|
1004
|
-
return f.warn = (u, I) => {
|
|
1005
|
-
u.includes("(client)") && u.includes("externalized") || v(u, I);
|
|
1006
|
-
}, f;
|
|
1007
|
-
})()
|
|
1008
|
-
}), c = a.environments.ssr;
|
|
1009
|
-
s(c) || (console.error(`
|
|
1010
|
-
Error: Vite environment is not runnable.
|
|
1011
|
-
Ensure vite.config.ts uses the default SSR environment.
|
|
1012
|
-
`), process.exit(1)), console.log(`
|
|
1013
|
-
KickJS dev server starting...`), console.log(` Entry: ${e}`), console.log(` HMR: enabled (Vite Environment Runner)
|
|
1014
|
-
`), await c.runner.import(`/${e}`);
|
|
1015
|
-
const d = [
|
|
1016
|
-
"kick.config.ts",
|
|
1017
|
-
"kick.config.js",
|
|
1018
|
-
"kick.config.mjs"
|
|
1019
|
-
];
|
|
1020
|
-
for (const l of d) {
|
|
1021
|
-
const f = m(l);
|
|
1022
|
-
a.watcher.add(f);
|
|
1023
|
-
}
|
|
1024
|
-
a.watcher.on("change", (l) => {
|
|
1025
|
-
const f = l.split("/").pop() ?? "";
|
|
1026
|
-
d.includes(f) && (console.log(`
|
|
1027
|
-
kick.config changed, restarting...
|
|
1028
|
-
`), a.restart());
|
|
1029
|
-
});
|
|
1030
|
-
const p = async () => {
|
|
1031
|
-
await a.close(), process.exit(0);
|
|
1032
|
-
};
|
|
1033
|
-
process.on("SIGINT", p), process.on("SIGTERM", p);
|
|
1034
|
-
}
|
|
1035
|
-
function Be(e) {
|
|
1036
|
-
e.command("dev").description("Start development server with Vite HMR (zero-downtime reload)").option("-e, --entry <file>", "Entry file", "src/index.ts").option("-p, --port <port>", "Port number").action(async (t) => {
|
|
1037
|
-
try {
|
|
1038
|
-
await Y(t.entry, t.port);
|
|
1039
|
-
} catch (r) {
|
|
1040
|
-
r.code === "ERR_MODULE_NOT_FOUND" && r.message?.includes("vite") ? console.error(`
|
|
1041
|
-
Error: vite is not installed.
|
|
1042
|
-
Run: pnpm add -D vite unplugin-swc
|
|
1043
|
-
`) : console.error(`
|
|
1044
|
-
Dev server failed:`, r.message ?? r), process.exit(1);
|
|
1045
|
-
}
|
|
1046
|
-
}), e.command("build").description("Build for production via Vite").action(async () => {
|
|
1047
|
-
console.log(`
|
|
1048
|
-
Building for production...
|
|
1049
|
-
`);
|
|
1050
|
-
const { createRequire: t } = await import("node:module"), { build: r } = await import(t(m("package.json")).resolve("vite"));
|
|
1051
|
-
await r({ configFile: m("vite.config.ts") });
|
|
1052
|
-
const o = (await w(process.cwd()))?.copyDirs ?? [];
|
|
1053
|
-
if (o.length > 0) {
|
|
1054
|
-
console.log(`
|
|
1055
|
-
Copying directories to dist...`);
|
|
1056
|
-
for (const n of o) {
|
|
1057
|
-
const i = typeof n == "string" ? n : n.src, s = typeof n == "string" ? g("dist", n) : n.dest ?? g("dist", i), a = m(i), c = m(s);
|
|
1058
|
-
if (!j(a)) {
|
|
1059
|
-
console.log(` ⚠ Skipped ${i} (not found)`);
|
|
1060
|
-
continue;
|
|
1061
|
-
}
|
|
1062
|
-
ge(c, { recursive: !0 }), fe(a, c, { recursive: !0 }), console.log(` ✓ ${i} → ${s}`);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
console.log(`
|
|
1066
|
-
Build complete.
|
|
1067
|
-
`);
|
|
1068
|
-
}), e.command("start").description("Start production server").option("-e, --entry <file>", "Entry file", "dist/index.js").option("-p, --port <port>", "Port number").action((t) => {
|
|
1069
|
-
const r = ["NODE_ENV=production"];
|
|
1070
|
-
t.port && r.push(`PORT=${t.port}`), K(`${r.join(" ")} node ${t.entry}`);
|
|
1071
|
-
}), e.command("dev:debug").description("Start dev server with Node.js inspector attached").option("-e, --entry <file>", "Entry file", "src/index.ts").option("-p, --port <port>", "Port number").option("--inspect-port <port>", "Inspector port", "9229").action(async (t) => {
|
|
1072
|
-
const r = t.inspectPort ?? "9229";
|
|
1073
|
-
process.env.NODE_OPTIONS = `--inspect=0.0.0.0:${r}`, console.log(` Debugger: ws://0.0.0.0:${r}`);
|
|
1074
|
-
try {
|
|
1075
|
-
await Y(t.entry, t.port);
|
|
1076
|
-
} catch (o) {
|
|
1077
|
-
console.error(`
|
|
1078
|
-
Dev server (debug) failed:`, o.message ?? o), process.exit(1);
|
|
1079
|
-
}
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
function We(e) {
|
|
1083
|
-
e.command("info").description("Print system and framework info").action(() => {
|
|
1084
|
-
console.log(`
|
|
1085
|
-
KickJS CLI
|
|
1086
|
-
|
|
1087
|
-
System:
|
|
1088
|
-
OS: ${Re()} ${xe()} (${De()})
|
|
1089
|
-
Node: ${process.version}
|
|
1090
|
-
|
|
1091
|
-
Packages:
|
|
1092
|
-
@forinda/kickjs-core workspace
|
|
1093
|
-
@forinda/kickjs-http workspace
|
|
1094
|
-
@forinda/kickjs-config workspace
|
|
1095
|
-
@forinda/kickjs-cli workspace
|
|
1096
|
-
`);
|
|
1097
|
-
});
|
|
1098
|
-
}
|
|
1099
|
-
function Ke(e, t) {
|
|
1100
|
-
if (t?.commands?.length)
|
|
1101
|
-
for (const r of t.commands) Ve(e, r);
|
|
1102
|
-
}
|
|
1103
|
-
function Ve(e, t) {
|
|
1104
|
-
const r = e.command(t.name).description(t.description);
|
|
1105
|
-
if (t.aliases) for (const o of t.aliases) r.alias(o);
|
|
1106
|
-
r.allowUnknownOption(!0), r.argument("[args...]", "Additional arguments passed to the command"), r.action((o) => {
|
|
1107
|
-
const n = o.join(" "), i = Array.isArray(t.steps) ? t.steps : [t.steps];
|
|
1108
|
-
for (const s of i) {
|
|
1109
|
-
const a = n ? `${s} ${n}` : s;
|
|
1110
|
-
console.log(` $ ${a}`);
|
|
1111
|
-
try {
|
|
1112
|
-
K(a);
|
|
1113
|
-
} catch {
|
|
1114
|
-
console.error(` Command failed: ${t.name}`), process.exitCode = 1;
|
|
1115
|
-
return;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
});
|
|
1119
|
-
}
|
|
1120
|
-
var x = (e) => `\x1B[${e}m`, C = x("0"), D = (e) => `${x("1")}${e}${C}`, k = (e) => `${x("2")}${e}${C}`, G = (e) => `${x("32")}${e}${C}`, T = (e) => `${x("31")}${e}${C}`, V = (e) => `${x("33")}${e}${C}`, Ze = (e) => `${x("36")}${e}${C}`, Xe = (e) => `${x("35")}${e}${C}`, et = (e) => `${x("34")}${e}${C}`, tt = {
|
|
1121
|
-
GET: G,
|
|
1122
|
-
POST: Ze,
|
|
1123
|
-
PUT: V,
|
|
1124
|
-
PATCH: Xe,
|
|
1125
|
-
DELETE: T
|
|
1126
|
-
};
|
|
1127
|
-
function ot(e) {
|
|
1128
|
-
return (tt[e] ?? k)(e.padEnd(7));
|
|
1129
|
-
}
|
|
1130
|
-
function rt(e) {
|
|
1131
|
-
const t = Math.floor(e / 86400), r = Math.floor(e % 86400 / 3600), o = Math.floor(e % 3600 / 60), n = e % 60, i = [];
|
|
1132
|
-
return t && i.push(`${t}d`), r && i.push(`${r}h`), o && i.push(`${o}m`), i.push(`${n}s`), i.join(" ");
|
|
1133
|
-
}
|
|
1134
|
-
async function nt(e) {
|
|
1135
|
-
const t = await fetch(e, { signal: AbortSignal.timeout(5e3) });
|
|
1136
|
-
if (!t.ok) throw new Error(`${t.status} ${t.statusText}`);
|
|
1137
|
-
return t.json();
|
|
1138
|
-
}
|
|
1139
|
-
async function O(e, t) {
|
|
1140
|
-
try {
|
|
1141
|
-
return await nt(`${e}${t}`);
|
|
1142
|
-
} catch {
|
|
1143
|
-
return null;
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
async function it(e) {
|
|
1147
|
-
const [t, r, o, n, i] = await Promise.all([
|
|
1148
|
-
O(e, "/health"),
|
|
1149
|
-
O(e, "/metrics"),
|
|
1150
|
-
O(e, "/routes"),
|
|
1151
|
-
O(e, "/container"),
|
|
1152
|
-
O(e, "/ws")
|
|
1153
|
-
]);
|
|
1154
|
-
return {
|
|
1155
|
-
health: t,
|
|
1156
|
-
metrics: r,
|
|
1157
|
-
routes: o,
|
|
1158
|
-
container: n,
|
|
1159
|
-
ws: i
|
|
1160
|
-
};
|
|
1161
|
-
}
|
|
1162
|
-
function st(e, t) {
|
|
1163
|
-
const { health: r, metrics: o, routes: n, container: i, ws: s } = t, a = k("─".repeat(60));
|
|
1164
|
-
if (console.log(), console.log(D(" KickJS Inspector") + k(` → ${e}`)), console.log(a), r) {
|
|
1165
|
-
const c = r.status === "healthy" ? G("● healthy") : T("● " + r.status);
|
|
1166
|
-
console.log(` ${D("Health:")} ${c}`);
|
|
1167
|
-
} else console.log(` ${D("Health:")} ${T("● unreachable")}`);
|
|
1168
|
-
if (o) {
|
|
1169
|
-
const c = ((o.errorRate ?? 0) * 100).toFixed(1), d = o.errorRate > 0.1 ? T : o.errorRate > 0 ? V : G;
|
|
1170
|
-
console.log(` ${D("Uptime:")} ${rt(o.uptimeSeconds)}`), console.log(` ${D("Requests:")} ${o.requests}`), console.log(` ${D("Errors:")} ${o.serverErrors} server, ${o.clientErrors ?? 0} client ${k("(")}${d(c + "%")}${k(")")}`);
|
|
1171
|
-
}
|
|
1172
|
-
if (i && console.log(` ${D("DI:")} ${i.count} bindings`), s && s.enabled && console.log(` ${D("WS:")} ${s.connections ?? 0} connections, ${s.namespaces ?? 0} namespaces`), n?.routes?.length) {
|
|
1173
|
-
console.log(), console.log(D(" Routes")), console.log(a), console.log(` ${k("METHOD")} ${k("PATH".padEnd(36))} ${k("CONTROLLER")}`);
|
|
1174
|
-
for (const c of n.routes) {
|
|
1175
|
-
const d = c.path.length > 36 ? c.path.slice(0, 33) + "..." : c.path.padEnd(36);
|
|
1176
|
-
console.log(` ${ot(c.method)} ${d} ${et(c.controller)}.${k(c.handler)}`);
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
console.log(a), console.log();
|
|
1180
|
-
}
|
|
1181
|
-
function at(e) {
|
|
1182
|
-
e.command("inspect [url]").description("Connect to a running KickJS app and display debug info").option("-p, --port <port>", "Override port").option("-w, --watch", "Poll every 5 seconds").option("-j, --json", "Output raw JSON").action(async (t, r) => {
|
|
1183
|
-
let o = t ?? "http://localhost:3000";
|
|
1184
|
-
if (r.port) try {
|
|
1185
|
-
const s = new URL(o);
|
|
1186
|
-
s.port = r.port, o = s.origin;
|
|
1187
|
-
} catch {
|
|
1188
|
-
o = `http://localhost:${r.port}`;
|
|
1189
|
-
}
|
|
1190
|
-
const n = `${o.replace(/\/$/, "")}/_debug`, i = async () => {
|
|
1191
|
-
try {
|
|
1192
|
-
const s = await it(n);
|
|
1193
|
-
r.json ? console.log(JSON.stringify(s, null, 2)) : st(o, s);
|
|
1194
|
-
} catch (s) {
|
|
1195
|
-
r.json ? console.log(JSON.stringify({ error: String(s) })) : (console.error(T(` ✖ Could not connect to ${o}`)), console.error(k(` ${s instanceof Error ? s.message : String(s)}`))), r.watch || (process.exitCode = 1);
|
|
1196
|
-
}
|
|
1197
|
-
};
|
|
1198
|
-
if (r.watch) {
|
|
1199
|
-
const s = async () => {
|
|
1200
|
-
process.stdout.write("\x1B[2J\x1B[H"), await i();
|
|
1201
|
-
};
|
|
1202
|
-
await s(), setInterval(s, 5e3);
|
|
1203
|
-
} else await i();
|
|
1204
|
-
});
|
|
1205
|
-
}
|
|
1206
|
-
var Q = {
|
|
1207
|
-
core: {
|
|
1208
|
-
pkg: "@forinda/kickjs-core",
|
|
1209
|
-
peers: [],
|
|
1210
|
-
description: "DI container, decorators, reactivity"
|
|
1211
|
-
},
|
|
1212
|
-
http: {
|
|
1213
|
-
pkg: "@forinda/kickjs-http",
|
|
1214
|
-
peers: ["express"],
|
|
1215
|
-
description: "Express 5, routing, middleware"
|
|
1216
|
-
},
|
|
1217
|
-
config: {
|
|
1218
|
-
pkg: "@forinda/kickjs-config",
|
|
1219
|
-
peers: [],
|
|
1220
|
-
description: "Zod-based env validation"
|
|
1221
|
-
},
|
|
1222
|
-
cli: {
|
|
1223
|
-
pkg: "@forinda/kickjs-cli",
|
|
1224
|
-
peers: [],
|
|
1225
|
-
description: "CLI tool and code generators",
|
|
1226
|
-
dev: !0
|
|
1227
|
-
},
|
|
1228
|
-
swagger: {
|
|
1229
|
-
pkg: "@forinda/kickjs-swagger",
|
|
1230
|
-
peers: [],
|
|
1231
|
-
description: "OpenAPI spec + Swagger UI + ReDoc"
|
|
1232
|
-
},
|
|
1233
|
-
graphql: {
|
|
1234
|
-
pkg: "@forinda/kickjs-graphql",
|
|
1235
|
-
peers: ["graphql"],
|
|
1236
|
-
description: "GraphQL resolvers + GraphiQL"
|
|
1237
|
-
},
|
|
1238
|
-
drizzle: {
|
|
1239
|
-
pkg: "@forinda/kickjs-drizzle",
|
|
1240
|
-
peers: ["drizzle-orm"],
|
|
1241
|
-
description: "Drizzle ORM adapter + query builder"
|
|
1242
|
-
},
|
|
1243
|
-
prisma: {
|
|
1244
|
-
pkg: "@forinda/kickjs-prisma",
|
|
1245
|
-
peers: ["@prisma/client"],
|
|
1246
|
-
description: "Prisma adapter + query builder"
|
|
1247
|
-
},
|
|
1248
|
-
ws: {
|
|
1249
|
-
pkg: "@forinda/kickjs-ws",
|
|
1250
|
-
peers: ["socket.io"],
|
|
1251
|
-
description: "WebSocket with @WsController decorators"
|
|
1252
|
-
},
|
|
1253
|
-
otel: {
|
|
1254
|
-
pkg: "@forinda/kickjs-otel",
|
|
1255
|
-
peers: ["@opentelemetry/api"],
|
|
1256
|
-
description: "OpenTelemetry tracing + metrics"
|
|
1257
|
-
},
|
|
1258
|
-
devtools: {
|
|
1259
|
-
pkg: "@forinda/kickjs-devtools",
|
|
1260
|
-
peers: [],
|
|
1261
|
-
description: "Development dashboard — routes, DI, metrics, health",
|
|
1262
|
-
dev: !0
|
|
1263
|
-
},
|
|
1264
|
-
auth: {
|
|
1265
|
-
pkg: "@forinda/kickjs-auth",
|
|
1266
|
-
peers: ["jsonwebtoken"],
|
|
1267
|
-
description: "Authentication — JWT, API key, and custom strategies"
|
|
1268
|
-
},
|
|
1269
|
-
mailer: {
|
|
1270
|
-
pkg: "@forinda/kickjs-mailer",
|
|
1271
|
-
peers: ["nodemailer"],
|
|
1272
|
-
description: "Email sending — SMTP, Resend, SES, or custom provider"
|
|
1273
|
-
},
|
|
1274
|
-
cron: {
|
|
1275
|
-
pkg: "@forinda/kickjs-cron",
|
|
1276
|
-
peers: ["croner"],
|
|
1277
|
-
description: "Cron job scheduling (production-grade with croner)"
|
|
1278
|
-
},
|
|
1279
|
-
queue: {
|
|
1280
|
-
pkg: "@forinda/kickjs-queue",
|
|
1281
|
-
peers: [],
|
|
1282
|
-
description: "Queue adapter (BullMQ/RabbitMQ/Kafka)"
|
|
1283
|
-
},
|
|
1284
|
-
"queue:bullmq": {
|
|
1285
|
-
pkg: "@forinda/kickjs-queue",
|
|
1286
|
-
peers: ["bullmq", "ioredis"],
|
|
1287
|
-
description: "Queue with BullMQ + Redis"
|
|
1288
|
-
},
|
|
1289
|
-
"queue:rabbitmq": {
|
|
1290
|
-
pkg: "@forinda/kickjs-queue",
|
|
1291
|
-
peers: ["amqplib"],
|
|
1292
|
-
description: "Queue with RabbitMQ"
|
|
1293
|
-
},
|
|
1294
|
-
"queue:kafka": {
|
|
1295
|
-
pkg: "@forinda/kickjs-queue",
|
|
1296
|
-
peers: ["kafkajs"],
|
|
1297
|
-
description: "Queue with Kafka"
|
|
1298
|
-
},
|
|
1299
|
-
"multi-tenant": {
|
|
1300
|
-
pkg: "@forinda/kickjs-multi-tenant",
|
|
1301
|
-
peers: [],
|
|
1302
|
-
description: "Tenant resolution middleware"
|
|
1303
|
-
},
|
|
1304
|
-
notifications: {
|
|
1305
|
-
pkg: "@forinda/kickjs-notifications",
|
|
1306
|
-
peers: [],
|
|
1307
|
-
description: "Multi-channel notifications — email, Slack, Discord, webhook"
|
|
1308
|
-
},
|
|
1309
|
-
testing: {
|
|
1310
|
-
pkg: "@forinda/kickjs-testing",
|
|
1311
|
-
peers: [],
|
|
1312
|
-
description: "Test utilities and TestModule builder",
|
|
1313
|
-
dev: !0
|
|
1314
|
-
}
|
|
1315
|
-
};
|
|
1316
|
-
function ct() {
|
|
1317
|
-
return j(m("pnpm-lock.yaml")) ? "pnpm" : j(m("yarn.lock")) ? "yarn" : "npm";
|
|
1318
|
-
}
|
|
1319
|
-
function Z() {
|
|
1320
|
-
console.log(`
|
|
1321
|
-
Available KickJS packages:
|
|
1322
|
-
`);
|
|
1323
|
-
const e = Math.max(...Object.keys(Q).map((t) => t.length));
|
|
1324
|
-
for (const [t, r] of Object.entries(Q)) {
|
|
1325
|
-
const o = t.padEnd(e + 2), n = r.peers.length ? ` (+ ${r.peers.join(", ")})` : "";
|
|
1326
|
-
console.log(` ${o} ${r.description}${n}`);
|
|
1327
|
-
}
|
|
1328
|
-
console.log(`
|
|
1329
|
-
Usage: kick add graphql drizzle otel`), console.log(" kick add queue:bullmq"), console.log();
|
|
1330
|
-
}
|
|
1331
|
-
function dt(e) {
|
|
1332
|
-
e.command("list").alias("ls").description("List all available KickJS packages").action(() => {
|
|
1333
|
-
Z();
|
|
1334
|
-
});
|
|
1335
|
-
}
|
|
1336
|
-
function pt(e) {
|
|
1337
|
-
e.command("add [packages...]").description("Add KickJS packages with their required dependencies").option("--pm <manager>", "Package manager override").option("-D, --dev", "Install as dev dependency").option("--list", "List all available packages").action(async (t, r) => {
|
|
1338
|
-
if (r.list || t.length === 0) {
|
|
1339
|
-
Z();
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
const o = r.pm ?? ct(), n = r.dev, i = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Set(), a = [];
|
|
1343
|
-
for (const c of t) {
|
|
1344
|
-
const d = Q[c];
|
|
1345
|
-
if (!d) {
|
|
1346
|
-
a.push(c);
|
|
1347
|
-
continue;
|
|
1348
|
-
}
|
|
1349
|
-
const p = n || d.dev ? s : i;
|
|
1350
|
-
p.add(d.pkg);
|
|
1351
|
-
for (const l of d.peers) p.add(l);
|
|
1352
|
-
}
|
|
1353
|
-
if (!(a.length > 0 && (console.log(`
|
|
1354
|
-
Unknown packages: ${a.join(", ")}`), console.log(` Run "kick add --list" to see available packages.
|
|
1355
|
-
`), i.size === 0 && s.size === 0))) {
|
|
1356
|
-
if (i.size > 0) {
|
|
1357
|
-
const c = Array.from(i), d = `${o} add ${c.join(" ")}`;
|
|
1358
|
-
console.log(`
|
|
1359
|
-
Installing ${c.length} dependency(ies):`);
|
|
1360
|
-
for (const p of c) console.log(` + ${p}`);
|
|
1361
|
-
console.log();
|
|
1362
|
-
try {
|
|
1363
|
-
q(d, { stdio: "inherit" });
|
|
1364
|
-
} catch {
|
|
1365
|
-
console.log(`
|
|
1366
|
-
Installation failed. Run manually:
|
|
1367
|
-
${d}
|
|
1368
|
-
`);
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
if (s.size > 0) {
|
|
1372
|
-
const c = Array.from(s), d = `${o} add -D ${c.join(" ")}`;
|
|
1373
|
-
console.log(`
|
|
1374
|
-
Installing ${c.length} dev dependency(ies):`);
|
|
1375
|
-
for (const p of c) console.log(` + ${p} (dev)`);
|
|
1376
|
-
console.log();
|
|
1377
|
-
try {
|
|
1378
|
-
q(d, { stdio: "inherit" });
|
|
1379
|
-
} catch {
|
|
1380
|
-
console.log(`
|
|
1381
|
-
Installation failed. Run manually:
|
|
1382
|
-
${d}
|
|
1383
|
-
`);
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
console.log(` Done!
|
|
1387
|
-
`);
|
|
1388
|
-
}
|
|
1389
|
-
});
|
|
1390
|
-
}
|
|
1391
|
-
function lt(e) {
|
|
1392
|
-
e.command("tinker").description("Interactive REPL with DI container and services loaded").option("-e, --entry <file>", "Entry file to load", "src/index.ts").action(async (t) => {
|
|
1393
|
-
const r = process.cwd(), o = m(r, t.entry);
|
|
1394
|
-
j(o) || (console.error(`
|
|
1395
|
-
Error: ${t.entry} not found.
|
|
1396
|
-
`), process.exit(1));
|
|
1397
|
-
const n = ut(r, "tsx");
|
|
1398
|
-
n || (console.error(`
|
|
1399
|
-
Error: tsx not found. Install it: pnpm add -D tsx
|
|
1400
|
-
`), process.exit(1));
|
|
1401
|
-
const i = mt(o, t.entry), s = g(r, ".kick-tinker.mjs"), { writeFileSync: a, unlinkSync: c } = await import("node:fs");
|
|
1402
|
-
a(s, i, "utf-8");
|
|
1403
|
-
try {
|
|
1404
|
-
const d = ue(s, [], {
|
|
1405
|
-
cwd: r,
|
|
1406
|
-
execPath: n,
|
|
1407
|
-
stdio: "inherit"
|
|
1408
|
-
});
|
|
1409
|
-
await new Promise((p) => {
|
|
1410
|
-
d.on("exit", () => p());
|
|
1411
|
-
});
|
|
1412
|
-
} finally {
|
|
1413
|
-
try {
|
|
1414
|
-
c(s);
|
|
1415
|
-
} catch {
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
});
|
|
1419
|
-
}
|
|
1420
|
-
function mt(e, t) {
|
|
1421
|
-
return `
|
|
1422
|
-
import 'reflect-metadata'
|
|
1423
|
-
|
|
1424
|
-
// Prevent bootstrap() from starting the HTTP server
|
|
1425
|
-
process.env.KICK_TINKER = '1'
|
|
1426
|
-
|
|
1427
|
-
console.log('\\n 🔧 KickJS Tinker')
|
|
1428
|
-
console.log(' Loading: ${t}\\n')
|
|
1429
|
-
|
|
1430
|
-
// Load core
|
|
1431
|
-
let Container, Logger, HttpException, HttpStatus
|
|
1432
|
-
try {
|
|
1433
|
-
const core = await import('@forinda/kickjs-core')
|
|
1434
|
-
Container = core.Container
|
|
1435
|
-
Logger = core.Logger
|
|
1436
|
-
HttpException = core.HttpException
|
|
1437
|
-
HttpStatus = core.HttpStatus
|
|
1438
|
-
} catch {
|
|
1439
|
-
console.error(' Error: @forinda/kickjs-core not found.')
|
|
1440
|
-
console.error(' Install it: pnpm add @forinda/kickjs-core\\n')
|
|
1441
|
-
process.exit(1)
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
// Load entry to trigger decorator registration
|
|
1445
|
-
try {
|
|
1446
|
-
await import('${ke(e).href}')
|
|
1447
|
-
} catch (err) {
|
|
1448
|
-
console.warn(' Warning: ' + err.message)
|
|
1449
|
-
console.warn(' Container may be partially initialized.\\n')
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
const container = Container.getInstance()
|
|
1453
|
-
|
|
1454
|
-
// Start REPL
|
|
1455
|
-
const repl = await import('node:repl')
|
|
1456
|
-
const server = repl.start({ prompt: 'kick> ', useGlobal: true })
|
|
1457
|
-
|
|
1458
|
-
server.context.container = container
|
|
1459
|
-
server.context.Container = Container
|
|
1460
|
-
server.context.resolve = (token) => container.resolve(token)
|
|
1461
|
-
server.context.Logger = Logger
|
|
1462
|
-
server.context.HttpException = HttpException
|
|
1463
|
-
server.context.HttpStatus = HttpStatus
|
|
1464
|
-
|
|
1465
|
-
console.log(' Available globals:')
|
|
1466
|
-
console.log(' container — DI container instance')
|
|
1467
|
-
console.log(' resolve(T) — shorthand for container.resolve(T)')
|
|
1468
|
-
console.log(' Container, Logger, HttpException, HttpStatus')
|
|
1469
|
-
console.log()
|
|
1470
|
-
|
|
1471
|
-
server.on('exit', () => {
|
|
1472
|
-
console.log('\\n Goodbye!\\n')
|
|
1473
|
-
process.exit(0)
|
|
1474
|
-
})
|
|
1475
|
-
`;
|
|
1476
|
-
}
|
|
1477
|
-
function ut(e, t) {
|
|
1478
|
-
let r = e;
|
|
1479
|
-
for (; ; ) {
|
|
1480
|
-
const o = g(r, "node_modules", ".bin", t);
|
|
1481
|
-
if (j(o)) return o;
|
|
1482
|
-
const n = m(r, "..");
|
|
1483
|
-
if (n === r) break;
|
|
1484
|
-
r = n;
|
|
1485
|
-
}
|
|
1486
|
-
return null;
|
|
1487
|
-
}
|
|
1488
|
-
function ft(e) {
|
|
1489
|
-
const t = N({
|
|
1490
|
-
input: process.stdin,
|
|
1491
|
-
output: process.stdout
|
|
1492
|
-
});
|
|
1493
|
-
return new Promise((r) => {
|
|
1494
|
-
t.question(` ${e} (y/N) `, (o) => {
|
|
1495
|
-
t.close(), r(o.trim().toLowerCase() === "y");
|
|
1496
|
-
});
|
|
1497
|
-
});
|
|
1498
|
-
}
|
|
1499
|
-
async function gt(e) {
|
|
1500
|
-
const { name: t, modulesDir: r, force: o } = e, n = e.pluralize !== !1, i = S(t), s = E(t), a = n ? _(i) : i, c = g(r, a);
|
|
1501
|
-
if (!await M(c)) {
|
|
1502
|
-
console.log(`
|
|
1503
|
-
Module not found: ${c}
|
|
1504
|
-
`);
|
|
1505
|
-
return;
|
|
1506
|
-
}
|
|
1507
|
-
if (!o && !await ft(`Delete module '${a}' at ${c}? This cannot be undone.`)) {
|
|
1508
|
-
console.log(`
|
|
1509
|
-
Cancelled.
|
|
1510
|
-
`);
|
|
1511
|
-
return;
|
|
1512
|
-
}
|
|
1513
|
-
await me(c, {
|
|
1514
|
-
recursive: !0,
|
|
1515
|
-
force: !0
|
|
1516
|
-
}), console.log(` Deleted: ${c}`);
|
|
1517
|
-
const d = g(r, "index.ts");
|
|
1518
|
-
if (await M(d)) {
|
|
1519
|
-
let p = await B(d, "utf-8");
|
|
1520
|
-
const l = p, f = new RegExp(`^import\\s*\\{\\s*${s}Module\\s*\\}\\s*from\\s*['\\./${a}']+.*\\n?`, "gm");
|
|
1521
|
-
p = p.replace(f, ""), p = p.replace(new RegExp(`\\s*,?\\s*${s}Module\\s*,?`, "g"), (v) => {
|
|
1522
|
-
const u = v.trimStart().startsWith(","), I = v.trimEnd().endsWith(",");
|
|
1523
|
-
return u && I ? "," : "";
|
|
1524
|
-
}), p = p.replace(/,(\s*])/, "$1"), p = p.replace(/\n{3,}/g, `
|
|
1525
|
-
|
|
1526
|
-
`), p !== l && (await W(d, p, "utf-8"), console.log(` Unregistered: ${s}Module from ${d}`));
|
|
1527
|
-
}
|
|
1528
|
-
console.log(`
|
|
1529
|
-
Module '${a}' removed.
|
|
1530
|
-
`);
|
|
1531
|
-
}
|
|
1532
|
-
function $t(e) {
|
|
1533
|
-
e.command("remove").alias("rm").description("Remove generated code").command("module <names...>").description("Remove one or more modules (e.g. kick rm module user task)").option("--modules-dir <dir>", "Modules directory").option("--no-pluralize", "Use singular module name").option("-f, --force", "Skip confirmation prompt").action(async (t, r) => {
|
|
1534
|
-
const o = R(await w(process.cwd())), n = r.modulesDir ?? o.dir ?? "src/modules", i = r.pluralize === !1 ? !1 : o.pluralize ?? !0;
|
|
1535
|
-
for (const s of t) await gt({
|
|
1536
|
-
name: s,
|
|
1537
|
-
modulesDir: m(n),
|
|
1538
|
-
force: r.force,
|
|
1539
|
-
pluralize: i
|
|
1540
|
-
});
|
|
1541
|
-
});
|
|
1542
|
-
}
|
|
1543
|
-
var yt = le(we(import.meta.url)), ht = JSON.parse($e(g(yt, "..", "package.json"), "utf-8"));
|
|
1544
|
-
async function wt() {
|
|
1545
|
-
const e = new ve();
|
|
1546
|
-
e.name("kick").description("KickJS — A production-grade, decorator-driven Node.js framework").version(ht.version);
|
|
1547
|
-
const t = await w(process.cwd());
|
|
1548
|
-
Ce(e), Ye(e), Be(e), We(e), at(e), pt(e), dt(e), lt(e), $t(e), Ke(e, t), e.showHelpAfterError(), await e.parseAsync(process.argv);
|
|
1549
|
-
}
|
|
1550
|
-
wt().catch((e) => {
|
|
1551
|
-
console.error(e instanceof Error ? e.message : e), process.exitCode = 1;
|
|
1552
|
-
});
|