@kanjijs/cli 0.2.0-beta.18 → 0.2.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/index.js +129 -3
- package/package.json +2 -2
- package/templates/starter/package.json +6 -6
package/README.md
CHANGED
|
@@ -39,7 +39,8 @@ kanjijs g resource products --repository # With Repository Pattern
|
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
- scaffolds `products.module.ts`, `products.controller.ts`, `products.service.ts`
|
|
42
|
-
- **
|
|
42
|
+
- **Full CRUD**: Generates `findAll`, `findOne`, `create`, `update`, and `remove` endpoints and methods.
|
|
43
|
+
- **Auto-generates** `products.controller.spec.ts` for unit testing with mocks for all CRUD methods.
|
|
43
44
|
- **Auto-updates** `src/app.module.ts` to import the new module! 🚀
|
|
44
45
|
|
|
45
46
|
### `g schema <name>`
|
package/dist/index.js
CHANGED
|
@@ -20004,9 +20004,52 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
|
20004
20004
|
import path2 from "path";
|
|
20005
20005
|
class GenerateCommand extends Command2 {
|
|
20006
20006
|
load(program2) {
|
|
20007
|
-
program2.command("g <type> <name>").description("Generate a new resource (e.g. 'kanjijs g resource users')").alias("generate").option("-r, --repository", "Generate with Repository pattern").action(async (type, name, options) => {
|
|
20007
|
+
program2.command("g <type> <name>").description("Generate a new resource (e.g. 'kanjijs g resource users')").alias("generate").option("-r, --repository", "Generate with Repository pattern").option("-m, --module <name>", "Generate schema in a specific module").action(async (type, name, options) => {
|
|
20008
|
+
if (type === "schema") {
|
|
20009
|
+
const lowerName2 = name.toLowerCase();
|
|
20010
|
+
let schemaDir = path2.join(process.cwd(), "src", "database", "schema");
|
|
20011
|
+
let relativePath = `./${lowerName2}`;
|
|
20012
|
+
if (options.module) {
|
|
20013
|
+
const moduleName = options.module.toLowerCase();
|
|
20014
|
+
schemaDir = path2.join(process.cwd(), "src", "modules", moduleName, "schemas");
|
|
20015
|
+
relativePath = `../../modules/${moduleName}/schemas/${lowerName2}`;
|
|
20016
|
+
}
|
|
20017
|
+
await import_fs_extra.default.ensureDir(schemaDir);
|
|
20018
|
+
const schemaPath = path2.join(schemaDir, `${lowerName2}.ts`);
|
|
20019
|
+
if (await import_fs_extra.default.pathExists(schemaPath)) {
|
|
20020
|
+
console.error(import_picocolors2.default.red(`Error: Schema ${lowerName2} already exists at ${schemaPath}`));
|
|
20021
|
+
process.exit(1);
|
|
20022
|
+
}
|
|
20023
|
+
const schemaTpl = `import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
|
|
20024
|
+
|
|
20025
|
+
export const ${lowerName2} = pgTable("${lowerName2}", {
|
|
20026
|
+
id: serial("id").primaryKey(),
|
|
20027
|
+
createdAt: timestamp("created_at").defaultNow(),
|
|
20028
|
+
updatedAt: timestamp("updated_at").defaultNow(),
|
|
20029
|
+
});
|
|
20030
|
+
`;
|
|
20031
|
+
await import_fs_extra.default.writeFile(schemaPath, schemaTpl);
|
|
20032
|
+
console.log(import_picocolors2.default.green(`CREATED ${options.module ? `src/modules/${options.module}/schemas/` : `src/database/schema/`}${lowerName2}.ts`));
|
|
20033
|
+
const indexDir = path2.join(process.cwd(), "src", "database", "schema");
|
|
20034
|
+
await import_fs_extra.default.ensureDir(indexDir);
|
|
20035
|
+
const indexPath = path2.join(indexDir, "index.ts");
|
|
20036
|
+
const exportStatement = `export * from "${relativePath}";`;
|
|
20037
|
+
if (await import_fs_extra.default.pathExists(indexPath)) {
|
|
20038
|
+
const content = await import_fs_extra.default.readFile(indexPath, "utf-8");
|
|
20039
|
+
if (!content.includes(exportStatement)) {
|
|
20040
|
+
await import_fs_extra.default.appendFile(indexPath, `
|
|
20041
|
+
${exportStatement}`);
|
|
20042
|
+
console.log(import_picocolors2.default.green(`UPDATED src/database/schema/index.ts`));
|
|
20043
|
+
}
|
|
20044
|
+
} else {
|
|
20045
|
+
await import_fs_extra.default.writeFile(indexPath, `${exportStatement}
|
|
20046
|
+
`);
|
|
20047
|
+
console.log(import_picocolors2.default.green(`CREATED src/database/schema/index.ts`));
|
|
20048
|
+
}
|
|
20049
|
+
return;
|
|
20050
|
+
}
|
|
20008
20051
|
if (type !== "resource") {
|
|
20009
|
-
console.error(import_picocolors2.default.red(`Unknown type: ${type}.
|
|
20052
|
+
console.error(import_picocolors2.default.red(`Unknown type: ${type}. Supported: 'resource', 'schema'.`));
|
|
20010
20053
|
process.exit(1);
|
|
20011
20054
|
}
|
|
20012
20055
|
const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
@@ -20022,6 +20065,26 @@ class GenerateCommand extends Command2 {
|
|
|
20022
20065
|
let serviceMethods = ` findAll() {
|
|
20023
20066
|
this.logger.info("Finding all ${lowerName}");
|
|
20024
20067
|
return "This action returns all ${lowerName}";
|
|
20068
|
+
}
|
|
20069
|
+
|
|
20070
|
+
findOne(id: number) {
|
|
20071
|
+
this.logger.info(\`Finding ${lowerName} with id \${id}\`);
|
|
20072
|
+
return \`This action returns a #\${id} ${lowerName}\`;
|
|
20073
|
+
}
|
|
20074
|
+
|
|
20075
|
+
create(data: any) {
|
|
20076
|
+
this.logger.info("Creating new ${lowerName}");
|
|
20077
|
+
return "This action adds a new ${lowerName}";
|
|
20078
|
+
}
|
|
20079
|
+
|
|
20080
|
+
update(id: number, data: any) {
|
|
20081
|
+
this.logger.info(\`Updating ${lowerName} with id \${id}\`);
|
|
20082
|
+
return \`This action updates a #\${id} ${lowerName}\`;
|
|
20083
|
+
}
|
|
20084
|
+
|
|
20085
|
+
remove(id: number) {
|
|
20086
|
+
this.logger.info(\`Deleting ${lowerName} with id \${id}\`);
|
|
20087
|
+
return \`This action removes a #\${id} ${lowerName}\`;
|
|
20025
20088
|
}`;
|
|
20026
20089
|
if (options.repository) {
|
|
20027
20090
|
const commonDir = path2.join(process.cwd(), "src", "common");
|
|
@@ -20121,8 +20184,21 @@ export class ${repositoryClass} extends BaseRepository<any> { // TODO: Replace '
|
|
|
20121
20184
|
return this.repo.findAll();
|
|
20122
20185
|
}
|
|
20123
20186
|
|
|
20187
|
+
async findOne(id: number) {
|
|
20188
|
+
this.logger.info(\`Finding ${lowerName} with id \${id}\`);
|
|
20189
|
+
return this.repo.findById(id);
|
|
20190
|
+
}
|
|
20191
|
+
|
|
20124
20192
|
async create(data: any) {
|
|
20125
20193
|
return this.repo.create(data);
|
|
20194
|
+
}
|
|
20195
|
+
|
|
20196
|
+
async update(id: number, data: any) {
|
|
20197
|
+
return this.repo.update(id, data);
|
|
20198
|
+
}
|
|
20199
|
+
|
|
20200
|
+
async remove(id: number) {
|
|
20201
|
+
return this.repo.delete(id);
|
|
20126
20202
|
}`;
|
|
20127
20203
|
}
|
|
20128
20204
|
const serviceTpl = `import { Injectable } from "@kanjijs/core";
|
|
@@ -20138,7 +20214,7 @@ ${serviceMethods}
|
|
|
20138
20214
|
`;
|
|
20139
20215
|
await import_fs_extra.default.writeFile(path2.join(targetDir, `${lowerName}.service.ts`), serviceTpl);
|
|
20140
20216
|
console.log(import_picocolors2.default.white(`CREATE ${lowerName}.service.ts`));
|
|
20141
|
-
const controllerTpl = `import { Controller, Get, Post,
|
|
20217
|
+
const controllerTpl = `import { Controller, Get, Post, Patch, Delete } from "@kanjijs/core";
|
|
20142
20218
|
import { type Context } from "hono";
|
|
20143
20219
|
import { ${className}Service } from "./${lowerName}.service";
|
|
20144
20220
|
import { Contract } from "@kanjijs/contracts";
|
|
@@ -20150,6 +20226,12 @@ const Create${className}Contract = Contract.json({
|
|
|
20150
20226
|
})
|
|
20151
20227
|
});
|
|
20152
20228
|
|
|
20229
|
+
const Update${className}Contract = Contract.json({
|
|
20230
|
+
body: z.object({
|
|
20231
|
+
name: z.string().optional(),
|
|
20232
|
+
})
|
|
20233
|
+
});
|
|
20234
|
+
|
|
20153
20235
|
@Controller("/${lowerName}")
|
|
20154
20236
|
export class ${className}Controller {
|
|
20155
20237
|
constructor(private readonly service: ${className}Service) {}
|
|
@@ -20159,12 +20241,31 @@ export class ${className}Controller {
|
|
|
20159
20241
|
return c.json(this.service.findAll());
|
|
20160
20242
|
}
|
|
20161
20243
|
|
|
20244
|
+
@Get("/:id")
|
|
20245
|
+
findOne(c: Context) {
|
|
20246
|
+
const id = Number(c.req.param("id"));
|
|
20247
|
+
return c.json(this.service.findOne(id));
|
|
20248
|
+
}
|
|
20249
|
+
|
|
20162
20250
|
@Post("/", { contract: Create${className}Contract })
|
|
20163
20251
|
create(c: Context) {
|
|
20164
20252
|
// Infer keys from contract (Contract-first)
|
|
20165
20253
|
const body = c.get("kanji.validated.body");
|
|
20166
20254
|
return c.json(this.service.create(body));
|
|
20167
20255
|
}
|
|
20256
|
+
|
|
20257
|
+
@Patch("/:id", { contract: Update${className}Contract })
|
|
20258
|
+
update(c: Context) {
|
|
20259
|
+
const id = Number(c.req.param("id"));
|
|
20260
|
+
const body = c.get("kanji.validated.body");
|
|
20261
|
+
return c.json(this.service.update(id, body));
|
|
20262
|
+
}
|
|
20263
|
+
|
|
20264
|
+
@Delete("/:id")
|
|
20265
|
+
remove(c: Context) {
|
|
20266
|
+
const id = Number(c.req.param("id"));
|
|
20267
|
+
return c.json(this.service.remove(id));
|
|
20268
|
+
}
|
|
20168
20269
|
}
|
|
20169
20270
|
`;
|
|
20170
20271
|
await import_fs_extra.default.writeFile(path2.join(targetDir, `${lowerName}.controller.ts`), controllerTpl);
|
|
@@ -20190,6 +20291,31 @@ export class ${className}Module {}
|
|
|
20190
20291
|
`;
|
|
20191
20292
|
await import_fs_extra.default.writeFile(path2.join(targetDir, `${lowerName}.module.ts`), moduleTpl);
|
|
20192
20293
|
console.log(import_picocolors2.default.white(`CREATE ${lowerName}.module.ts`));
|
|
20294
|
+
const testTpl = `import { Test } from "@kanjijs/testing";
|
|
20295
|
+
import { ${className}Controller } from "./${lowerName}.controller";
|
|
20296
|
+
import { ${className}Service } from "./${lowerName}.service";
|
|
20297
|
+
|
|
20298
|
+
test("${className}Controller", async () => {
|
|
20299
|
+
const moduleRef = await Test.createTestingModule({
|
|
20300
|
+
controllers: [${className}Controller],
|
|
20301
|
+
providers: [${className}Service],
|
|
20302
|
+
})
|
|
20303
|
+
.overrideProvider(${className}Service)
|
|
20304
|
+
.useValue({
|
|
20305
|
+
findAll: () => [],
|
|
20306
|
+
findOne: () => ({}),
|
|
20307
|
+
create: () => ({}),
|
|
20308
|
+
update: () => ({}),
|
|
20309
|
+
remove: () => ({}),
|
|
20310
|
+
})
|
|
20311
|
+
.compile();
|
|
20312
|
+
|
|
20313
|
+
const controller = moduleRef.get(${className}Controller);
|
|
20314
|
+
expect(controller).toBeDefined();
|
|
20315
|
+
});
|
|
20316
|
+
`;
|
|
20317
|
+
await import_fs_extra.default.writeFile(path2.join(targetDir, `${lowerName}.controller.spec.ts`), testTpl);
|
|
20318
|
+
console.log(import_picocolors2.default.white(`CREATE ${lowerName}.controller.spec.ts`));
|
|
20193
20319
|
const appModulePath = path2.join(process.cwd(), "src", "app.module.ts");
|
|
20194
20320
|
if (await import_fs_extra.default.pathExists(appModulePath)) {
|
|
20195
20321
|
let content = await import_fs_extra.default.readFile(appModulePath, "utf-8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanjijs/cli",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"kanji": "./dist/index.js"
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"fs-extra": "^11.3.3",
|
|
22
22
|
"picocolors": "^1.1.1",
|
|
23
23
|
"openapi-typescript-codegen": "^0.25.0",
|
|
24
|
-
"@kanjijs/openapi": "^0.2.0-beta.
|
|
24
|
+
"@kanjijs/openapi": "^0.2.0-beta.19"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/fs-extra": "^11.0.4"
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"start": "bun run src/main.ts"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@kanjijs/core": "^0.2.0-beta.
|
|
11
|
-
"@kanjijs/platform-bun": "^0.2.0-beta.
|
|
12
|
-
"@kanjijs/platform-hono": "^0.2.0-beta.
|
|
13
|
-
"@kanjijs/auth": "^0.2.0-beta.
|
|
14
|
-
"@kanjijs/logger": "^0.2.0-beta.
|
|
15
|
-
"@kanjijs/throttler": "^0.2.0-beta.
|
|
10
|
+
"@kanjijs/core": "^0.2.0-beta.19",
|
|
11
|
+
"@kanjijs/platform-bun": "^0.2.0-beta.19",
|
|
12
|
+
"@kanjijs/platform-hono": "^0.2.0-beta.19",
|
|
13
|
+
"@kanjijs/auth": "^0.2.0-beta.19",
|
|
14
|
+
"@kanjijs/logger": "^0.2.0-beta.19",
|
|
15
|
+
"@kanjijs/throttler": "^0.2.0-beta.19",
|
|
16
16
|
"hono": "^4.0.0",
|
|
17
17
|
"reflect-metadata": "^0.2.0",
|
|
18
18
|
"zod": "^3.0.0"
|