sonamu 0.7.53 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/dist/api/config.d.ts +9 -1
  2. package/dist/api/config.d.ts.map +1 -1
  3. package/dist/api/config.js +1 -1
  4. package/dist/api/sonamu.d.ts +21 -1
  5. package/dist/api/sonamu.d.ts.map +1 -1
  6. package/dist/api/sonamu.js +159 -65
  7. package/dist/auth/plugins/entity-definitions/anonymous.d.ts +10 -0
  8. package/dist/auth/plugins/entity-definitions/anonymous.d.ts.map +1 -0
  9. package/dist/auth/plugins/entity-definitions/anonymous.js +23 -0
  10. package/dist/auth/plugins/entity-definitions/api-key.d.ts +9 -0
  11. package/dist/auth/plugins/entity-definitions/api-key.d.ts.map +1 -0
  12. package/dist/auth/plugins/entity-definitions/api-key.js +199 -0
  13. package/dist/auth/plugins/entity-definitions/index.d.ts +6 -0
  14. package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
  15. package/dist/auth/plugins/entity-definitions/index.js +20 -2
  16. package/dist/auth/plugins/entity-definitions/jwt.d.ts +9 -0
  17. package/dist/auth/plugins/entity-definitions/jwt.d.ts.map +1 -0
  18. package/dist/auth/plugins/entity-definitions/jwt.js +67 -0
  19. package/dist/auth/plugins/entity-definitions/organization.d.ts +9 -0
  20. package/dist/auth/plugins/entity-definitions/organization.d.ts.map +1 -0
  21. package/dist/auth/plugins/entity-definitions/organization.js +424 -0
  22. package/dist/auth/plugins/entity-definitions/passkey.d.ts +10 -0
  23. package/dist/auth/plugins/entity-definitions/passkey.d.ts.map +1 -0
  24. package/dist/auth/plugins/entity-definitions/passkey.js +129 -0
  25. package/dist/auth/plugins/entity-definitions/sso.d.ts +10 -0
  26. package/dist/auth/plugins/entity-definitions/sso.d.ts.map +1 -0
  27. package/dist/auth/plugins/entity-definitions/sso.js +110 -0
  28. package/dist/auth/plugins/entity-definitions/types.d.ts +1 -1
  29. package/dist/auth/plugins/entity-definitions/types.d.ts.map +1 -1
  30. package/dist/auth/plugins/entity-definitions/types.js +1 -1
  31. package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
  32. package/dist/auth/plugins/wrappers/admin.js +2 -4
  33. package/dist/auth/plugins/wrappers/anonymous.d.ts +18 -0
  34. package/dist/auth/plugins/wrappers/anonymous.d.ts.map +1 -0
  35. package/dist/auth/plugins/wrappers/anonymous.js +26 -0
  36. package/dist/auth/plugins/wrappers/api-key.d.ts +18 -0
  37. package/dist/auth/plugins/wrappers/api-key.d.ts.map +1 -0
  38. package/dist/auth/plugins/wrappers/api-key.js +38 -0
  39. package/dist/auth/plugins/wrappers/index.d.ts +6 -0
  40. package/dist/auth/plugins/wrappers/index.d.ts.map +1 -1
  41. package/dist/auth/plugins/wrappers/index.js +7 -1
  42. package/dist/auth/plugins/wrappers/jwt.d.ts +18 -0
  43. package/dist/auth/plugins/wrappers/jwt.d.ts.map +1 -0
  44. package/dist/auth/plugins/wrappers/jwt.js +30 -0
  45. package/dist/auth/plugins/wrappers/organization.d.ts +18 -0
  46. package/dist/auth/plugins/wrappers/organization.d.ts.map +1 -0
  47. package/dist/auth/plugins/wrappers/organization.js +67 -0
  48. package/dist/auth/plugins/wrappers/passkey.d.ts +18 -0
  49. package/dist/auth/plugins/wrappers/passkey.d.ts.map +1 -0
  50. package/dist/auth/plugins/wrappers/passkey.js +32 -0
  51. package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
  52. package/dist/auth/plugins/wrappers/phone-number.js +2 -4
  53. package/dist/auth/plugins/wrappers/sso.d.ts +853 -0
  54. package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -0
  55. package/dist/auth/plugins/wrappers/sso.js +36 -0
  56. package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
  57. package/dist/auth/plugins/wrappers/two-factor.js +2 -4
  58. package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
  59. package/dist/auth/plugins/wrappers/username.js +2 -4
  60. package/dist/bin/build-config.d.ts +2 -2
  61. package/dist/bin/build-config.js +6 -7
  62. package/dist/bin/cli.js +417 -32
  63. package/dist/bin/fixture.d.ts +27 -0
  64. package/dist/bin/fixture.d.ts.map +1 -0
  65. package/dist/bin/fixture.js +245 -0
  66. package/dist/cache/decorator.d.ts +4 -3
  67. package/dist/cache/decorator.d.ts.map +1 -1
  68. package/dist/cache/decorator.js +5 -4
  69. package/dist/cone/cone-generator.d.ts +33 -0
  70. package/dist/cone/cone-generator.d.ts.map +1 -0
  71. package/dist/cone/cone-generator.js +286 -0
  72. package/dist/database/_batch_update.d.ts.map +1 -1
  73. package/dist/database/_batch_update.js +16 -2
  74. package/dist/database/puri-subset.test-d.js +1 -1
  75. package/dist/database/puri-subset.types.d.ts +1 -1
  76. package/dist/database/puri-subset.types.d.ts.map +1 -1
  77. package/dist/database/puri-subset.types.js +1 -1
  78. package/dist/database/puri.d.ts +4 -0
  79. package/dist/database/puri.d.ts.map +1 -1
  80. package/dist/database/puri.js +20 -2
  81. package/dist/database/upsert-builder.d.ts.map +1 -1
  82. package/dist/database/upsert-builder.js +19 -3
  83. package/dist/dict/en.d.ts +15 -0
  84. package/dist/dict/en.d.ts.map +1 -1
  85. package/dist/dict/en.js +2 -1
  86. package/dist/dict/ko.d.ts +15 -0
  87. package/dist/dict/ko.d.ts.map +1 -1
  88. package/dist/dict/ko.js +2 -1
  89. package/dist/dict/rc-keys.d.ts +28 -0
  90. package/dist/dict/rc-keys.d.ts.map +1 -1
  91. package/dist/dict/rc-keys.js +31 -1
  92. package/dist/dict/sd.d.ts.map +1 -1
  93. package/dist/dict/sd.js +20 -4
  94. package/dist/entity/entity-manager.d.ts +298 -2
  95. package/dist/entity/entity-manager.d.ts.map +1 -1
  96. package/dist/entity/entity-manager.js +4 -1
  97. package/dist/entity/entity-template-cone.d.ts +14 -0
  98. package/dist/entity/entity-template-cone.d.ts.map +1 -0
  99. package/dist/entity/entity-template-cone.js +222 -0
  100. package/dist/entity/entity.d.ts +47 -2
  101. package/dist/entity/entity.d.ts.map +1 -1
  102. package/dist/entity/entity.js +161 -14
  103. package/dist/ssr/renderer.js +3 -3
  104. package/dist/syncer/api-parser.js +12 -1
  105. package/dist/syncer/checksum.d.ts +0 -14
  106. package/dist/syncer/checksum.d.ts.map +1 -1
  107. package/dist/syncer/checksum.js +1 -23
  108. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  109. package/dist/syncer/syncer-actions.js +8 -2
  110. package/dist/syncer/syncer.d.ts +1 -1
  111. package/dist/syncer/syncer.d.ts.map +1 -1
  112. package/dist/syncer/syncer.js +17 -10
  113. package/dist/tasks/workflow-manager.d.ts +13 -1
  114. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  115. package/dist/tasks/workflow-manager.js +18 -1
  116. package/dist/template/entity-converter.js +4 -4
  117. package/dist/template/helpers.d.ts +10 -0
  118. package/dist/template/helpers.d.ts.map +1 -1
  119. package/dist/template/helpers.js +48 -1
  120. package/dist/template/implementations/entry-server.template.d.ts +1 -1
  121. package/dist/template/implementations/entry-server.template.js +7 -2
  122. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  123. package/dist/template/implementations/generated.template.js +5 -1
  124. package/dist/template/implementations/generated_http.template.d.ts +1 -0
  125. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  126. package/dist/template/implementations/generated_http.template.js +6 -2
  127. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  128. package/dist/template/implementations/generated_sso.template.js +29 -8
  129. package/dist/template/implementations/queries.template.d.ts.map +1 -1
  130. package/dist/template/implementations/queries.template.js +9 -1
  131. package/dist/template/implementations/sd.template.d.ts +1 -1
  132. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  133. package/dist/template/implementations/sd.template.js +28 -4
  134. package/dist/template/implementations/services.template.d.ts.map +1 -1
  135. package/dist/template/implementations/services.template.js +12 -12
  136. package/dist/template/implementations/view_form.template.d.ts +11 -7
  137. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  138. package/dist/template/implementations/view_form.template.js +97 -87
  139. package/dist/template/implementations/view_list.template.d.ts +3 -3
  140. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  141. package/dist/template/implementations/view_list.template.js +115 -109
  142. package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
  143. package/dist/template/implementations/view_search_input.template.js +18 -14
  144. package/dist/template/zod-converter.d.ts.map +1 -1
  145. package/dist/template/zod-converter.js +95 -7
  146. package/dist/testing/_relation-graph.js +1 -1
  147. package/dist/testing/data-explorer.d.ts +61 -0
  148. package/dist/testing/data-explorer.d.ts.map +1 -0
  149. package/dist/testing/data-explorer.js +274 -0
  150. package/dist/testing/faker-mappings.d.ts +20 -0
  151. package/dist/testing/faker-mappings.d.ts.map +1 -0
  152. package/dist/testing/faker-mappings.js +421 -0
  153. package/dist/testing/fixture-generator.d.ts +161 -0
  154. package/dist/testing/fixture-generator.d.ts.map +1 -0
  155. package/dist/testing/fixture-generator.js +954 -0
  156. package/dist/testing/fixture-manager.d.ts +6 -1
  157. package/dist/testing/fixture-manager.d.ts.map +1 -1
  158. package/dist/testing/fixture-manager.js +72 -4
  159. package/dist/testing/index.d.ts +3 -0
  160. package/dist/testing/index.d.ts.map +1 -1
  161. package/dist/testing/index.js +4 -1
  162. package/dist/types/types.d.ts +1520 -26
  163. package/dist/types/types.d.ts.map +1 -1
  164. package/dist/types/types.js +136 -22
  165. package/dist/ui/ai-client.d.ts.map +1 -1
  166. package/dist/ui/ai-client.js +9 -4
  167. package/dist/ui/api.d.ts.map +1 -1
  168. package/dist/ui/api.js +303 -24
  169. package/dist/ui-web/assets/index-CsUr-_pV.js +254 -0
  170. package/dist/ui-web/assets/index-T42zzs1K.css +1 -0
  171. package/dist/ui-web/index.html +2 -2
  172. package/dist/utils/fs-utils.d.ts +2 -1
  173. package/dist/utils/fs-utils.d.ts.map +1 -1
  174. package/dist/utils/fs-utils.js +14 -3
  175. package/package.json +19 -11
  176. package/src/api/config.ts +12 -1
  177. package/src/api/sonamu.ts +179 -65
  178. package/src/auth/plugins/entity-definitions/anonymous.ts +17 -0
  179. package/src/auth/plugins/entity-definitions/api-key.ts +93 -0
  180. package/src/auth/plugins/entity-definitions/index.ts +18 -0
  181. package/src/auth/plugins/entity-definitions/jwt.ts +35 -0
  182. package/src/auth/plugins/entity-definitions/organization.ts +215 -0
  183. package/src/auth/plugins/entity-definitions/passkey.ts +64 -0
  184. package/src/auth/plugins/entity-definitions/sso.ts +62 -0
  185. package/src/auth/plugins/entity-definitions/types.ts +11 -1
  186. package/src/auth/plugins/wrappers/admin.ts +1 -3
  187. package/src/auth/plugins/wrappers/anonymous.ts +30 -0
  188. package/src/auth/plugins/wrappers/api-key.ts +42 -0
  189. package/src/auth/plugins/wrappers/index.ts +6 -0
  190. package/src/auth/plugins/wrappers/jwt.ts +34 -0
  191. package/src/auth/plugins/wrappers/organization.ts +73 -0
  192. package/src/auth/plugins/wrappers/passkey.ts +36 -0
  193. package/src/auth/plugins/wrappers/phone-number.ts +1 -3
  194. package/src/auth/plugins/wrappers/sso.ts +40 -0
  195. package/src/auth/plugins/wrappers/two-factor.ts +1 -3
  196. package/src/auth/plugins/wrappers/username.ts +1 -3
  197. package/src/bin/build-config.ts +6 -6
  198. package/src/bin/cli.ts +452 -31
  199. package/src/bin/fixture.ts +302 -0
  200. package/src/cache/decorator.ts +4 -3
  201. package/src/cone/cone-generator.ts +363 -0
  202. package/src/database/_batch_update.ts +11 -0
  203. package/src/database/puri-subset.test-d.ts +13 -13
  204. package/src/database/puri-subset.types.ts +1 -1
  205. package/src/database/puri.ts +43 -1
  206. package/src/database/upsert-builder.ts +16 -2
  207. package/src/dict/en.ts +1 -0
  208. package/src/dict/ko.ts +1 -0
  209. package/src/dict/rc-keys.ts +32 -0
  210. package/src/dict/sd.ts +23 -3
  211. package/src/entity/entity-manager.ts +4 -0
  212. package/src/entity/entity-template-cone.ts +298 -0
  213. package/src/entity/entity.ts +189 -13
  214. package/src/shared/app.shared.ts.txt +5 -0
  215. package/src/shared/web.shared.ts.txt +9 -5
  216. package/src/skills/project/README.md +21 -0
  217. package/src/skills/project/architecture.md +373 -0
  218. package/src/skills/project/business-logic.md +270 -0
  219. package/src/skills/project/requirements.md +160 -0
  220. package/src/skills/sonamu/SKILL.md +168 -3
  221. package/src/skills/sonamu/api.md +102 -0
  222. package/src/skills/sonamu/database.md +220 -1
  223. package/src/skills/sonamu/entity-relations.md +89 -1
  224. package/src/skills/sonamu/fixture-cli.md +501 -0
  225. package/src/skills/sonamu/frontend.md +214 -0
  226. package/src/skills/sonamu/i18n.md +95 -0
  227. package/src/skills/sonamu/model.md +153 -0
  228. package/src/skills/sonamu/project-init.md +178 -8
  229. package/src/skills/sonamu/scaffolding.md +112 -0
  230. package/src/skills/sonamu/subset.md +9 -3
  231. package/src/skills/sonamu/testing.md +287 -2
  232. package/src/skills/sonamu/workflow.md +70 -5
  233. package/src/ssr/renderer.ts +2 -2
  234. package/src/syncer/api-parser.ts +12 -0
  235. package/src/syncer/checksum.ts +0 -38
  236. package/src/syncer/syncer-actions.ts +7 -1
  237. package/src/syncer/syncer.ts +16 -5
  238. package/src/tasks/workflow-manager.ts +29 -8
  239. package/src/template/entity-converter.ts +3 -3
  240. package/src/template/helpers.ts +49 -0
  241. package/src/template/implementations/entry-server.template.ts +1 -1
  242. package/src/template/implementations/generated.template.ts +4 -0
  243. package/src/template/implementations/generated_http.template.ts +1 -0
  244. package/src/template/implementations/generated_sso.template.ts +40 -11
  245. package/src/template/implementations/queries.template.ts +8 -0
  246. package/src/template/implementations/sd.template.ts +22 -3
  247. package/src/template/implementations/services.template.ts +11 -10
  248. package/src/template/implementations/view_form.template.ts +111 -101
  249. package/src/template/implementations/view_list.template.ts +120 -119
  250. package/src/template/implementations/view_search_input.template.ts +17 -13
  251. package/src/template/zod-converter.ts +103 -6
  252. package/src/testing/_relation-graph.ts +1 -1
  253. package/src/testing/data-explorer.ts +427 -0
  254. package/src/testing/faker-mappings.ts +434 -0
  255. package/src/testing/fixture-generator.ts +1166 -0
  256. package/src/testing/fixture-manager.ts +91 -6
  257. package/src/testing/index.ts +3 -0
  258. package/src/types/types.ts +222 -26
  259. package/src/ui/ai-client.ts +9 -1
  260. package/src/ui/api.ts +429 -23
  261. package/src/utils/fs-utils.ts +14 -1
  262. package/dist/template/implementations/view_enums_select.template.d.ts +0 -17
  263. package/dist/template/implementations/view_enums_select.template.d.ts.map +0 -1
  264. package/dist/template/implementations/view_enums_select.template.js +0 -62
  265. package/dist/template/implementations/view_id_async_select.template.d.ts +0 -17
  266. package/dist/template/implementations/view_id_async_select.template.d.ts.map +0 -1
  267. package/dist/template/implementations/view_id_async_select.template.js +0 -125
  268. package/dist/ui-web/assets/index-Bd_2AkLb.css +0 -1
  269. package/dist/ui-web/assets/index-BpSbhQWo.js +0 -225
  270. package/src/template/implementations/view_enums_select.template.ts +0 -65
  271. package/src/template/implementations/view_id_async_select.template.ts +0 -139
@@ -1,10 +1,12 @@
1
- import inflection from "inflection";
2
1
  import { unique } from "radashi";
3
2
  import { z } from "zod";
4
3
  import { EntityManager, type EntityNamesRecord } from "../../entity/entity-manager";
5
- import type { RenderingNode, TemplateKey, TemplateOptions } from "../../types/types";
6
- import { getEnumInfoFromColName, getRelationPropFromColName } from "../helpers";
7
- import type { RenderedTemplate } from "../template";
4
+ import type { RenderingNode, TemplateOptions } from "../../types/types";
5
+ import {
6
+ getEnumInfoFromColName,
7
+ getRelationNameFromColumnName,
8
+ getRelationPropFromColName,
9
+ } from "../helpers";
8
10
  import { Template } from "../template";
9
11
 
10
12
  export class Template__view_form extends Template {
@@ -36,26 +38,32 @@ export class Template__view_form extends Template {
36
38
 
37
39
  renderColumnImport(entityId: string, col: RenderingNode) {
38
40
  if (col.renderType === "enums") {
39
- const { id, targetEntityNames } = getEnumInfoFromColName(entityId, col.name);
40
- const componentId = `${id}Select`;
41
- return `import { ${componentId} } from "@/components/${targetEntityNames.fs}/${componentId}";`;
42
- } else if (col.renderType === "number-fk_id") {
41
+ const { id } = getEnumInfoFromColName(entityId, col.name);
42
+ return { type: "enum" as const, enumId: id };
43
+ } else if (col.renderType === "number-fk_id" || col.renderType === "string-fk_id") {
43
44
  try {
44
45
  const relProp = getRelationPropFromColName(entityId, col.name.replace("_id", ""));
45
- const targetNames = EntityManager.getNamesFromId(relProp.with);
46
- const componentId = `${relProp.with}IdAsyncSelect`;
47
- return `import { ${componentId} } from "@/components/${targetNames.fs}/${componentId}";`;
46
+ return { type: "fk" as const, entityId: relProp.with };
47
+ } catch {
48
+ return null;
49
+ }
50
+ } else if (col.renderType === "array" && col.name.endsWith("_ids")) {
51
+ // ManyToMany relation의 FK 배열
52
+ try {
53
+ const baseName = col.name.replace(/_ids$/, "");
54
+ const relProp = getRelationPropFromColName(entityId, baseName);
55
+ return { type: "fk" as const, entityId: relProp.with };
48
56
  } catch {
49
- return "";
57
+ return null;
50
58
  }
51
- } else {
52
- throw new Error(`렌더 불가능한 임포트 ${col.name} ${col.renderType}`);
53
59
  }
60
+ return null;
54
61
  }
55
62
 
56
- renderColumn(entityId: string, col: RenderingNode, names: EntityNamesRecord): string {
63
+ renderColumn(entityId: string, col: RenderingNode): string {
57
64
  const regExpr = `{...register("${col.name}")}`;
58
- const placeholder = `{SD("entity.${entityId}.${col.name}")}`;
65
+ const placeholderName = getRelationNameFromColumnName(entityId, col.name);
66
+ const placeholder = `{SD("entity.${entityId}.${placeholderName}")}`;
59
67
 
60
68
  switch (col.renderType) {
61
69
  case "string-plain":
@@ -70,6 +78,7 @@ export class Template__view_form extends Template {
70
78
  ${regExpr}
71
79
  />`;
72
80
  case "number-id":
81
+ case "string-id":
73
82
  return `<input type="hidden" ${regExpr} />`;
74
83
  case "number-plain":
75
84
  return `<Input type="number" className="h-8 text-xs bg-white" placeholder=${placeholder} ${regExpr} />`;
@@ -93,28 +102,44 @@ export class Template__view_form extends Template {
93
102
  />`;
94
103
  case "enums":
95
104
  try {
96
- let enumId: string;
97
- if (col.name === "orderBy") {
98
- enumId = `${names.capital}${inflection.camelize(col.name)}Select`;
99
- } else {
100
- const { id } = getEnumInfoFromColName(entityId, col.name);
101
- enumId = `${id}Select`;
102
- }
103
- return `<${enumId} ${regExpr} ${col.optional || col.nullable ? "clearable" : ""} />`;
105
+ const { id } = getEnumInfoFromColName(entityId, col.name);
106
+ return `<EnumSelect
107
+ enum={${id}}
108
+ labels={${id}Label}
109
+ ${regExpr}
110
+ />`;
104
111
  } catch {
105
112
  return `<Input className="h-8 text-xs bg-white" ${regExpr} />`;
106
113
  }
107
114
  case "number-fk_id":
115
+ case "string-fk_id":
108
116
  try {
109
117
  const relProp = getRelationPropFromColName(entityId, col.name.replace("_id", ""));
110
- const fkId = `${relProp.with}IdAsyncSelect`;
111
- return `<${fkId} subset="A" ${regExpr} ${
112
- col.optional || col.nullable ? "clearable" : ""
113
- } className="h-8 text-xs" />`;
118
+ return `<IdAsyncSelect
119
+ config={${relProp.with}AsyncIdConfig}
120
+ subset="A"
121
+ ${regExpr}
122
+ />`;
114
123
  } catch {
115
124
  return `<Input type="number" className="h-8 text-xs bg-white" placeholder=${placeholder} ${regExpr} />`;
116
125
  }
117
126
  case "array":
127
+ // ManyToMany relation의 FK 배열인지 확인
128
+ if (col.name.endsWith("_ids")) {
129
+ try {
130
+ const baseName = col.name.replace(/_ids$/, "");
131
+ const relProp = getRelationPropFromColName(entityId, baseName);
132
+ return `<IdAsyncSelect
133
+ config={${relProp.with}AsyncIdConfig}
134
+ subset="A"
135
+ multiple
136
+ ${regExpr}
137
+ />`;
138
+ } catch {
139
+ return `<Input className="h-8 text-xs bg-white" placeholder="${col.name}" ${regExpr} />`;
140
+ }
141
+ }
142
+ return `<Input className="h-8 text-xs bg-white" placeholder="${col.name}" ${regExpr} />`;
118
143
  case "object":
119
144
  return `<Input className="h-8 text-xs bg-white" placeholder="${col.name}" ${regExpr} />`;
120
145
  default:
@@ -192,66 +217,40 @@ export class Template__view_form extends Template {
192
217
 
193
218
  const defaultValue = this.resolveDefaultValue(columns);
194
219
 
195
- // 프리 템플릿
196
- const preTemplates: RenderedTemplate["preTemplates"] = (columns as RenderingNode[])
197
- .filter((col) => {
198
- if (col.name === "id") {
199
- return false;
200
- } else if (col.name.endsWith("_id") || col.renderType === "number-id") {
201
- try {
202
- getRelationPropFromColName(entityId, col.name.replace("_id", ""));
203
- return true;
204
- } catch {
205
- return false;
206
- }
207
- } else if (col.renderType === "enums") {
208
- try {
209
- getEnumInfoFromColName(entityId, col.name);
210
- return true;
211
- } catch {
212
- return false;
213
- }
214
- }
215
- return false;
216
- })
217
- .map((col) => {
218
- let key: TemplateKey;
219
- let targetMdId = entityId;
220
- let enumId: string | undefined;
221
- if (col.renderType === "enums") {
222
- key = "view_enums_select";
223
- const { targetEntityNames: targetMDNames, id } = getEnumInfoFromColName(
224
- entityId,
225
- col.name,
226
- );
227
- targetMdId = targetMDNames.capital;
228
- enumId = id;
229
- } else {
230
- key = "view_id_async_select";
231
- const relProp = getRelationPropFromColName(entityId, col.name.replace("_id", ""));
232
- targetMdId = relProp.with;
233
- }
220
+ // enum과 FK에 대한 import 정보 수집
221
+ const enumImports = new Set<string>();
222
+ const fkConfigImports = new Set<string>();
234
223
 
235
- return {
236
- key: key as TemplateKey,
237
- options: {
238
- entityId: targetMdId,
239
- node: col,
240
- enumId,
241
- },
242
- };
243
- })
244
- .filter((preTemplate) => {
245
- if (preTemplate.key === "view_id_async_select") {
246
- try {
247
- EntityManager.get(preTemplate.options.entityId);
248
- return true;
249
- } catch {
250
- return false;
251
- }
252
- }
253
- return true;
254
- });
224
+ columns.forEach((col) => {
225
+ if (col.renderType === "enums") {
226
+ try {
227
+ const { id } = getEnumInfoFromColName(entityId, col.name);
228
+ enumImports.add(id);
229
+ } catch {}
230
+ } else if (col.renderType === "number-fk_id" || col.renderType === "string-fk_id") {
231
+ try {
232
+ const relProp = getRelationPropFromColName(entityId, col.name.replace("_id", ""));
233
+ fkConfigImports.add(relProp.with);
234
+ } catch {}
235
+ } else if (
236
+ col.renderType === "string-plain" &&
237
+ col.name.endsWith("_id") &&
238
+ col.name !== "id"
239
+ ) {
240
+ // string FK 처리 (자신의 PK인 id는 제외)
241
+ try {
242
+ const relProp = getRelationPropFromColName(entityId, col.name.replace("_id", ""));
243
+ fkConfigImports.add(relProp.with);
244
+ } catch {}
245
+ } else if (col.renderType === "array" && col.name.endsWith("_ids")) {
246
+ // ManyToMany relation의 FK 배열
247
+ try {
248
+ const baseName = col.name.replace(/_ids$/, "");
249
+ const relProp = getRelationPropFromColName(entityId, baseName);
250
+ fkConfigImports.add(relProp.with);
251
+ } catch {}
252
+ }
253
+ });
255
254
 
256
255
  return {
257
256
  ...this.getTargetAndPath(names),
@@ -262,7 +261,7 @@ import {
262
261
  CardContent,
263
262
  CardHeader,
264
263
  CardTitle,
265
- Input,${columns.some((col) => col.renderType === "string-plain" && col.zodType instanceof z.ZodString && (col.zodType.maxLength ?? 0) > 256) ? "\n Textarea," : ""}${columns.some((col) => col.renderType === "enums") ? "\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue," : ""}${columns.some((col) => col.renderType === "boolean") ? "\n Switch," : ""}${columns.some((col) => ["json-sonamufile", "json-sonamufile-array"].includes(col.renderType)) ? "\n FileInput," : ""}${columns.some((col) => ["string-datetime", "string-date", "datetime"].includes(col.renderType)) ? "\n DateInput," : ""}
264
+ Input,${columns.some((col) => col.renderType === "string-plain" && col.zodType instanceof z.ZodString && (col.zodType.maxLength ?? 0) > 256) ? "\n Textarea," : ""}${columns.some((col) => col.renderType === "enums") ? "\n EnumSelect," : ""}${columns.some((col) => col.renderType === "number-fk_id" || col.renderType === "string-fk_id" || (col.renderType === "array" && col.name.endsWith("_ids"))) ? "\n IdAsyncSelect," : ""}${columns.some((col) => col.renderType === "boolean") ? "\n Switch," : ""}${columns.some((col) => ["json-sonamufile", "json-sonamufile-array"].includes(col.renderType)) ? "\n FileInput," : ""}${columns.some((col) => ["string-datetime", "string-date", "datetime"].includes(col.renderType)) ? "\n DateInput," : ""}
266
265
  } from "@sonamu-kit/react-components/components";
267
266
  import { useTypeForm } from "@sonamu-kit/react-components/lib";
268
267
  import { useQueryClient } from "@tanstack/react-query";
@@ -291,14 +290,13 @@ import type { ${names.capital}SubsetA } from "@/services/sonamu.generated";${
291
290
  : ""
292
291
  }
293
292
  import { defaultCatch } from "@/services/sonamu.shared";
294
- import { ${names.capital}SaveParams } from "@/services/${names.fs}/${names.fs}.types";
295
- ${unique(
296
- columns
297
- .filter((col) => ["number-fk_id", "enums"].includes(col.renderType))
298
- .map((col) => {
299
- return this.renderColumnImport(entityId, col);
300
- }),
301
- ).join("\n")}
293
+ import { ${names.capital}SaveParams } from "@/services/${names.fs}/${names.fs}.types";${
294
+ fkConfigImports.size > 0
295
+ ? `\nimport { ${Array.from(fkConfigImports)
296
+ .map((entity) => `${entity}AsyncIdConfig`)
297
+ .join(", ")} } from "@/services/services.generated";`
298
+ : ""
299
+ }
302
300
  import { SD } from "@/i18n/sd.generated";
303
301
 
304
302
  import ArrowLeftIcon from "~icons/lucide/arrow-left";
@@ -374,10 +372,22 @@ ${(() => {
374
372
  ...prevForm,
375
373
  ...row,${(() => {
376
374
  // relation 필드들을 찾아서 변환 코드 생성
375
+ // number FK, string FK (자신의 PK 제외), ManyToMany FK 배열만 필터링
377
376
  const relationFields = columns
378
- .filter((col) => col.renderType === "number-fk_id")
377
+ .filter(
378
+ (col) =>
379
+ col.renderType === "number-fk_id" ||
380
+ col.renderType === "string-fk_id" ||
381
+ (col.renderType === "array" && col.name.endsWith("_ids")),
382
+ )
379
383
  .map((col) => {
380
- const relationName = col.name.replace(/_id$/, "");
384
+ // ManyToMany(array) 처리
385
+ if (col.renderType === "array" && col.name.endsWith("_ids")) {
386
+ const relationName = getRelationNameFromColumnName(entityId, col.name);
387
+ return `\n ${col.name}: row.${relationName}?.map((r) => r.id) ?? [],`;
388
+ }
389
+ // FK(number, string) 처리
390
+ const relationName = getRelationNameFromColumnName(entityId, col.name);
381
391
  if (col.nullable) {
382
392
  return `\n ${col.name}: row.${relationName}?.id ?? null,`;
383
393
  } else {
@@ -483,10 +493,11 @@ ${columns
483
493
  }
484
494
  return col.label;
485
495
  })();
496
+ const labelName = getRelationNameFromColumnName(entityId, col.name);
486
497
  return ` {/* ${label} */}
487
498
  <div className="space-y-2">
488
- <label className="block text-xs mb-1 text-gray-600">{SD("entity.${entityId}.${col.name}")}</label>
489
- ${this.renderColumn(entityId, col, names)}
499
+ <label className="block text-xs mb-1 text-gray-600">{SD("entity.${entityId}.${labelName}")}</label>
500
+ ${this.renderColumn(entityId, col)}
490
501
  </div>`;
491
502
  })
492
503
  .join("\n\n")}
@@ -518,7 +529,6 @@ ${columns
518
529
  }
519
530
  `.trim(),
520
531
  importKeys: [],
521
- preTemplates,
522
532
  };
523
533
  }
524
534
  }