sonamu 0.4.10 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/{base-model-w9EuyYif.d.ts → base-model-Br6krkwK.d.ts} +1 -1
  2. package/dist/{base-model-ChAfKHR7.d.mts → base-model-BvVra-8f.d.mts} +1 -1
  3. package/dist/bin/cli.js +51 -51
  4. package/dist/bin/cli.mjs +2 -2
  5. package/dist/{chunk-C7NTXZWZ.mjs → chunk-FKZK27YL.mjs} +2 -2
  6. package/dist/{chunk-IPTFUZN2.js → chunk-FYLFH3Q6.js} +100 -100
  7. package/dist/{chunk-I7O4VXTH.js → chunk-IEMX4VPN.js} +4 -4
  8. package/dist/{chunk-QT3GBIMP.js → chunk-INTZUNZ6.js} +7 -7
  9. package/dist/{chunk-IPFCELQ3.mjs → chunk-JQJTQQ7D.mjs} +2 -2
  10. package/dist/{chunk-EEUCHV4P.mjs → chunk-LNZTU4JC.mjs} +70 -41
  11. package/dist/chunk-LNZTU4JC.mjs.map +1 -0
  12. package/dist/{chunk-M6MCZP64.mjs → chunk-NPLUHS5L.mjs} +2 -2
  13. package/dist/{chunk-E2I4OSFY.js → chunk-ZLFDB43J.js} +70 -41
  14. package/dist/chunk-ZLFDB43J.js.map +1 -0
  15. package/dist/database/drivers/knex/base-model.d.mts +2 -2
  16. package/dist/database/drivers/knex/base-model.d.ts +2 -2
  17. package/dist/database/drivers/knex/base-model.js +8 -8
  18. package/dist/database/drivers/knex/base-model.mjs +3 -3
  19. package/dist/database/drivers/kysely/base-model.d.mts +2 -2
  20. package/dist/database/drivers/kysely/base-model.d.ts +2 -2
  21. package/dist/database/drivers/kysely/base-model.js +9 -9
  22. package/dist/database/drivers/kysely/base-model.mjs +3 -3
  23. package/dist/index.d.mts +13 -5
  24. package/dist/index.d.ts +13 -5
  25. package/dist/index.js +18 -7
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +14 -3
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/{model-BF9CDic2.d.ts → model-DWoinpJ7.d.mts} +73 -5
  30. package/dist/{model-BF9CDic2.d.mts → model-DWoinpJ7.d.ts} +73 -5
  31. package/package.json +1 -1
  32. package/src/api/base-frame.ts +14 -0
  33. package/src/api/decorators.ts +2 -1
  34. package/src/index.ts +1 -0
  35. package/src/syncer/syncer.ts +77 -40
  36. package/src/templates/service.template.ts +4 -6
  37. package/src/types/types.ts +11 -1
  38. package/dist/chunk-E2I4OSFY.js.map +0 -1
  39. package/dist/chunk-EEUCHV4P.mjs.map +0 -1
  40. /package/dist/{chunk-C7NTXZWZ.mjs.map → chunk-FKZK27YL.mjs.map} +0 -0
  41. /package/dist/{chunk-IPTFUZN2.js.map → chunk-FYLFH3Q6.js.map} +0 -0
  42. /package/dist/{chunk-I7O4VXTH.js.map → chunk-IEMX4VPN.js.map} +0 -0
  43. /package/dist/{chunk-QT3GBIMP.js.map → chunk-INTZUNZ6.js.map} +0 -0
  44. /package/dist/{chunk-IPFCELQ3.mjs.map → chunk-JQJTQQ7D.mjs.map} +0 -0
  45. /package/dist/{chunk-M6MCZP64.mjs.map → chunk-NPLUHS5L.mjs.map} +0 -0
@@ -469,11 +469,59 @@ declare const TemplateOptions: z.ZodObject<{
469
469
  entityId: string;
470
470
  }>;
471
471
  service: z.ZodObject<{
472
- entityId: z.ZodString;
472
+ namesRecord: z.ZodObject<{
473
+ fs: z.ZodString;
474
+ fsPlural: z.ZodString;
475
+ camel: z.ZodString;
476
+ camelPlural: z.ZodString;
477
+ capital: z.ZodString;
478
+ capitalPlural: z.ZodString;
479
+ upper: z.ZodString;
480
+ constant: z.ZodString;
481
+ }, "strip", z.ZodTypeAny, {
482
+ fs: string;
483
+ fsPlural: string;
484
+ camel: string;
485
+ camelPlural: string;
486
+ capital: string;
487
+ capitalPlural: string;
488
+ upper: string;
489
+ constant: string;
490
+ }, {
491
+ fs: string;
492
+ fsPlural: string;
493
+ camel: string;
494
+ camelPlural: string;
495
+ capital: string;
496
+ capitalPlural: string;
497
+ upper: string;
498
+ constant: string;
499
+ }>;
500
+ modelTsPath: z.ZodString;
473
501
  }, "strip", z.ZodTypeAny, {
474
- entityId: string;
502
+ namesRecord: {
503
+ fs: string;
504
+ fsPlural: string;
505
+ camel: string;
506
+ camelPlural: string;
507
+ capital: string;
508
+ capitalPlural: string;
509
+ upper: string;
510
+ constant: string;
511
+ };
512
+ modelTsPath: string;
475
513
  }, {
476
- entityId: string;
514
+ namesRecord: {
515
+ fs: string;
516
+ fsPlural: string;
517
+ camel: string;
518
+ camelPlural: string;
519
+ capital: string;
520
+ capitalPlural: string;
521
+ upper: string;
522
+ constant: string;
523
+ };
524
+ modelTsPath: string;
477
525
  }>;
478
526
  view_list: z.ZodObject<{
479
527
  entityId: z.ZodString;
@@ -611,7 +659,17 @@ declare const TemplateOptions: z.ZodObject<{
611
659
  entityId: string;
612
660
  };
613
661
  service: {
614
- entityId: string;
662
+ namesRecord: {
663
+ fs: string;
664
+ fsPlural: string;
665
+ camel: string;
666
+ camelPlural: string;
667
+ capital: string;
668
+ capitalPlural: string;
669
+ upper: string;
670
+ constant: string;
671
+ };
672
+ modelTsPath: string;
615
673
  };
616
674
  view_list: {
617
675
  entityId: string;
@@ -683,7 +741,17 @@ declare const TemplateOptions: z.ZodObject<{
683
741
  entityId: string;
684
742
  };
685
743
  service: {
686
- entityId: string;
744
+ namesRecord: {
745
+ fs: string;
746
+ fsPlural: string;
747
+ camel: string;
748
+ camelPlural: string;
749
+ capital: string;
750
+ capitalPlural: string;
751
+ upper: string;
752
+ constant: string;
753
+ };
754
+ modelTsPath: string;
687
755
  };
688
756
  view_list: {
689
757
  entityId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonamu",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "description": "Sonamu — TypeScript Fullstack API Framework",
5
5
  "keywords": [
6
6
  "typescript",
@@ -0,0 +1,14 @@
1
+ import { Knex } from "knex";
2
+ import { DB } from "../database/db";
3
+ import { DBPreset } from "../database/types";
4
+ import { UpsertBuilder } from "../database/upsert-builder";
5
+
6
+ export abstract class BaseFrameClass {
7
+ getDB(which: DBPreset): Knex {
8
+ return DB.getDB(which) as Knex;
9
+ }
10
+
11
+ getUpsertBuilder() {
12
+ return new UpsertBuilder<"knex">();
13
+ }
14
+ }
@@ -49,8 +49,9 @@ export function api(options: ApiDecoratorOptions = {}) {
49
49
  return function (target: Object, propertyKey: string) {
50
50
  const modelName = target.constructor.name.match(/(.+)Class$/)![1];
51
51
  const methodName = propertyKey;
52
+
52
53
  const defaultPath = `/${inflection.camelize(
53
- modelName.replace(/Model$/, ""),
54
+ modelName.replace(/Model$/, "").replace(/Frame$/, ""),
54
55
  true
55
56
  )}/${inflection.camelize(propertyKey, true)}`;
56
57
 
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from "./api/code-converters";
2
2
  export * from "./api/context";
3
3
  export * from "./api/decorators";
4
4
  export * from "./api/sonamu";
5
+ export * from "./api/base-frame";
5
6
  export * from "./database/db";
6
7
  export * from "./database/upsert-builder";
7
8
  export * from "./database/types";
@@ -5,7 +5,7 @@ import crypto from "crypto";
5
5
  import equal from "fast-deep-equal";
6
6
  import _ from "lodash";
7
7
  import inflection from "inflection";
8
- import { EntityManager } from "../entity/entity-manager";
8
+ import { EntityManager, EntityNamesRecord } from "../entity/entity-manager";
9
9
  import ts from "typescript";
10
10
  import {
11
11
  ApiParam,
@@ -79,7 +79,13 @@ import { Template__kysely_interface } from "../templates/kysely_types.template";
79
79
  import { DB } from "../database/db";
80
80
  import { setTimeout as setTimeoutPromises } from "timers/promises";
81
81
 
82
- type FileType = "model" | "types" | "functions" | "generated" | "entity";
82
+ type FileType =
83
+ | "model"
84
+ | "types"
85
+ | "functions"
86
+ | "generated"
87
+ | "entity"
88
+ | "frame";
83
89
  type GlobPattern = {
84
90
  [key in FileType]: string;
85
91
  };
@@ -200,7 +206,7 @@ export class Syncer {
200
206
  // 다른 부분 찾아 액션
201
207
  const diffGroups = _.groupBy(diffFiles, (r) => {
202
208
  const matched = r.match(
203
- /\.(model|types|functions|entity|generated)\.[tj]s/
209
+ /\.(model|types|functions|entity|generated|frame)\.[tj]s/
204
210
  );
205
211
  return matched![1];
206
212
  }) as unknown as DiffGroups;
@@ -255,12 +261,44 @@ export class Syncer {
255
261
  }
256
262
 
257
263
  // 트리거: model
258
- if (diffTypes.includes("model")) {
259
- const entityIds = this.getEntityIdFromPath(diffGroups["model"]);
264
+ if (diffTypes.includes("model") || diffTypes.includes("frame")) {
260
265
  console.log("// 액션: 서비스 생성");
261
- await this.actionGenerateServices(entityIds);
266
+ const mergedGroup = [
267
+ ...(diffGroups["model"] ?? []),
268
+ ...(diffGroups["frame"] ?? []),
269
+ ];
270
+ const params: { namesRecord: EntityNamesRecord; modelTsPath: string }[] =
271
+ mergedGroup.map((modelPath) => {
272
+ if (modelPath.endsWith(".model.js")) {
273
+ const entityId = this.getEntityIdFromPath([modelPath])[0];
274
+ return {
275
+ namesRecord: EntityManager.getNamesFromId(entityId),
276
+ modelTsPath: path.join(
277
+ Sonamu.apiRootPath,
278
+ modelPath
279
+ .replace("/dist/", "/src/")
280
+ .replace(".model.js", ".model.ts")
281
+ ),
282
+ };
283
+ }
284
+ if (modelPath.endsWith("frame.js")) {
285
+ const [, frameName] = modelPath.match(/.+\/(.+)\.frame.js$/) ?? [];
286
+ return {
287
+ namesRecord: EntityManager.getNamesFromId(frameName),
288
+ modelTsPath: path.join(
289
+ Sonamu.apiRootPath,
290
+ modelPath
291
+ .replace("/dist/", "/src/")
292
+ .replace(".frame.js", ".frame.ts")
293
+ ),
294
+ };
295
+ }
296
+ throw new Error("not reachable");
297
+ });
298
+ await this.actionGenerateServices(params);
299
+
262
300
  console.log("// 액션: HTTP파일 생성");
263
- await this.actionGenerateHttps(entityIds);
301
+ await this.actionGenerateHttps();
264
302
  }
265
303
 
266
304
  // 저장
@@ -292,19 +330,18 @@ export class Syncer {
292
330
  .flat();
293
331
  }
294
332
 
295
- async actionGenerateServices(entityIds: string[]): Promise<string[]> {
333
+ async actionGenerateServices(
334
+ paramsArray: {
335
+ namesRecord: EntityNamesRecord;
336
+ modelTsPath: string;
337
+ }[]
338
+ ): Promise<string[]> {
296
339
  return (
297
340
  await Promise.all(
298
- entityIds.map(async (entityId) =>
299
- this.generateTemplate(
300
- "service",
301
- {
302
- entityId,
303
- },
304
- {
305
- overwrite: true,
306
- }
307
- )
341
+ paramsArray.map(async (params) =>
342
+ this.generateTemplate("service", params, {
343
+ overwrite: true,
344
+ })
308
345
  )
309
346
  )
310
347
  )
@@ -312,10 +349,10 @@ export class Syncer {
312
349
  .flat();
313
350
  }
314
351
 
315
- async actionGenerateHttps(entityIds: string[]): Promise<string[]> {
352
+ async actionGenerateHttps(): Promise<string[]> {
316
353
  const [res] = await this.generateTemplate(
317
354
  "generated_http",
318
- { entityId: entityIds[0] },
355
+ {},
319
356
  { overwrite: true }
320
357
  );
321
358
  return res;
@@ -383,6 +420,7 @@ export class Syncer {
383
420
  functions: Sonamu.apiRootPath + "/src/application/**/*.functions.ts",
384
421
  /* compiled-JS 체크 */
385
422
  model: Sonamu.apiRootPath + "/dist/application/**/*.model.js",
423
+ frame: Sonamu.apiRootPath + "/dist/application/**/*.frame.js",
386
424
  };
387
425
 
388
426
  const filePaths = (
@@ -525,6 +563,12 @@ export class Syncer {
525
563
  method.methodName === api.methodName
526
564
  );
527
565
  });
566
+ if (currentModelApis.length === 0) {
567
+ // const p = path.join(tmpdir(), "sonamu-syncer-error.json");
568
+ // writeFileSync(p, JSON.stringify(registeredApis, null, 2));
569
+ // execSync(`open ${p}`);
570
+ throw new Error(`현재 파일에 사전 등록된 API가 없습니다. ${filePath}`);
571
+ }
528
572
 
529
573
  // 등록된 API에 현재 메소드 타입 정보 확장
530
574
  const extendedApis = currentModelApis.map((api) => {
@@ -722,7 +766,7 @@ export class Syncer {
722
766
  async autoloadApis() {
723
767
  const pathPattern = path.join(
724
768
  Sonamu.apiRootPath,
725
- "/src/application/**/*.model.ts"
769
+ "/src/application/**/*.{model,frame}.ts"
726
770
  );
727
771
  // console.debug(chalk.yellow(`autoload:APIs @ ${pathPattern}`));
728
772
 
@@ -737,7 +781,7 @@ export class Syncer {
737
781
  async autoloadModels(): Promise<{ [modelName: string]: unknown }> {
738
782
  const pathPattern = path.join(
739
783
  Sonamu.apiRootPath,
740
- "dist/application/**/*.model.js"
784
+ "dist/application/**/*.{model,frame}.js"
741
785
  );
742
786
  // console.debug(chalk.yellow(`autoload:models @ ${pathPattern}`));
743
787
 
@@ -752,7 +796,9 @@ export class Syncer {
752
796
  .map(({ imported }) => Object.entries(imported))
753
797
  .flat();
754
798
  this.models = Object.fromEntries(
755
- functions.filter(([name]) => name.endsWith("Model"))
799
+ functions.filter(
800
+ ([name]) => name.endsWith("Model") || name.endsWith("Frame")
801
+ )
756
802
  );
757
803
  return this.models;
758
804
  }
@@ -839,22 +885,13 @@ export class Syncer {
839
885
  const template: Template = this.getTemplate(key);
840
886
 
841
887
  let extra: unknown[] = [];
842
- if (
843
- ["service", "generated_http", "model", "view_list", "view_form"].includes(
844
- key
845
- )
846
- ) {
847
- const entityId = (options as TemplateOptions["service"]).entityId;
848
-
849
- if (key === "service" || key === "generated_http") {
850
- // service 필요 정보 (API 리스트)
851
- const entity = EntityManager.get(entityId!);
852
- const modelTsPath = `${path.join(
853
- Sonamu.apiRootPath,
854
- "/src/application"
855
- )}/${entity.names.fs}/${entity.names.fs}.model.ts`;
856
- extra = [await this.readApisFromFile(modelTsPath)];
857
- } else if (key === "view_list" || key === "model") {
888
+ if (key === "service") {
889
+ // service 필요 정보 (API 리스트)
890
+ const { modelTsPath } = options as TemplateOptions["service"];
891
+ extra = [await this.readApisFromFile(modelTsPath)];
892
+ } else if (["model", "view_list", "view_form"].includes(key)) {
893
+ const entityId = (options as TemplateOptions["model"]).entityId;
894
+ if (key === "view_list" || key === "model") {
858
895
  // view_list 필요 정보 (컬럼 노드, 리스트파라미터 노드)
859
896
  const columnsNode = await this.getColumnsNode(entityId, "A");
860
897
  const listParamsZodType = await this.getZodTypeById(
@@ -1383,7 +1420,7 @@ export class Syncer {
1383
1420
  // generate schemas, types
1384
1421
  await Promise.all([
1385
1422
  this.actionGenerateSchemas(),
1386
- ...(form.entityId === undefined
1423
+ ...(form.parentId === undefined
1387
1424
  ? [
1388
1425
  this.generateTemplate("init_types", {
1389
1426
  entityId: form.entityId,
@@ -1,7 +1,7 @@
1
1
  import inflection from "inflection";
2
2
  import _ from "lodash";
3
3
  import { TemplateOptions } from "../types/types";
4
- import { EntityManager, EntityNamesRecord } from "../entity/entity-manager";
4
+ import { EntityNamesRecord } from "../entity/entity-manager";
5
5
  import { ApiParamType, ApiParam } from "../types/types";
6
6
  import {
7
7
  apiParamTypeToTsType,
@@ -24,9 +24,7 @@ export class Template__service extends Template {
24
24
  };
25
25
  }
26
26
 
27
- render({ entityId }: TemplateOptions["service"], apis: ExtendedApi[]) {
28
- const names = EntityManager.getNamesFromId(entityId);
29
-
27
+ render({ namesRecord }: TemplateOptions["service"], apis: ExtendedApi[]) {
30
28
  // 서비스 TypeSource
31
29
  const { lines, importKeys } = this.getTypeSource(apis);
32
30
 
@@ -36,7 +34,7 @@ export class Template__service extends Template {
36
34
  );
37
35
 
38
36
  return {
39
- ...this.getTargetAndPath(names),
37
+ ...this.getTargetAndPath(namesRecord),
40
38
  body: lines.join("\n"),
41
39
  importKeys: importKeys.filter(
42
40
  (key) => ["ListResult"].includes(key) === false
@@ -154,7 +152,7 @@ export class Template__service extends Template {
154
152
  })
155
153
  .join("\n\n");
156
154
 
157
- return `export namespace ${modelName.replace(/Model$/, "Service")} {
155
+ return `export namespace ${modelName.replace(/Model$/, "Service").replace(/Frame$/, "Service")} {
158
156
  ${methodCodes}
159
157
  }`;
160
158
  })
@@ -686,7 +686,17 @@ export const TemplateOptions = z.object({
686
686
  entityId: z.string(),
687
687
  }),
688
688
  service: z.object({
689
- entityId: z.string(),
689
+ namesRecord: z.object({
690
+ fs: z.string(),
691
+ fsPlural: z.string(),
692
+ camel: z.string(),
693
+ camelPlural: z.string(),
694
+ capital: z.string(),
695
+ capitalPlural: z.string(),
696
+ upper: z.string(),
697
+ constant: z.string(),
698
+ }),
699
+ modelTsPath: z.string(),
690
700
  }),
691
701
  view_list: z.object({
692
702
  entityId: z.string(),