@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 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
- - **Auto-generates** `products.controller.spec.ts` for unit testing.
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}. Only 'resource' is supported.`));
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, Body } from "@kanjijs/core";
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.18",
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.18"
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.18",
11
- "@kanjijs/platform-bun": "^0.2.0-beta.18",
12
- "@kanjijs/platform-hono": "^0.2.0-beta.18",
13
- "@kanjijs/auth": "^0.2.0-beta.18",
14
- "@kanjijs/logger": "^0.2.0-beta.18",
15
- "@kanjijs/throttler": "^0.2.0-beta.18",
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"