sonamu 0.4.13 → 0.5.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 (371) hide show
  1. package/.swcrc +15 -0
  2. package/dist/api/base-frame.d.ts +8 -0
  3. package/dist/api/base-frame.d.ts.map +1 -0
  4. package/dist/api/base-frame.js +2 -0
  5. package/dist/api/base-frame.js.map +1 -0
  6. package/dist/api/caster.d.ts +5 -0
  7. package/dist/api/caster.d.ts.map +1 -0
  8. package/dist/api/caster.js +2 -0
  9. package/dist/api/caster.js.map +1 -0
  10. package/dist/api/code-converters.d.ts +23 -0
  11. package/dist/api/code-converters.d.ts.map +1 -0
  12. package/dist/api/code-converters.js +2 -0
  13. package/dist/api/code-converters.js.map +1 -0
  14. package/dist/api/context.d.ts +16 -0
  15. package/dist/api/context.d.ts.map +1 -0
  16. package/dist/api/context.js +2 -0
  17. package/dist/api/context.js.map +1 -0
  18. package/dist/api/decorators.d.ts +50 -0
  19. package/dist/api/decorators.d.ts.map +1 -0
  20. package/dist/api/decorators.js +2 -0
  21. package/dist/api/decorators.js.map +1 -0
  22. package/dist/api/index.d.ts +8 -0
  23. package/dist/api/index.d.ts.map +1 -0
  24. package/dist/api/index.js +2 -0
  25. package/dist/api/index.js.map +1 -0
  26. package/dist/api/sonamu.d.ts +83 -0
  27. package/dist/api/sonamu.d.ts.map +1 -0
  28. package/dist/api/sonamu.js +2 -0
  29. package/dist/api/sonamu.js.map +1 -0
  30. package/dist/api/sonamu.types.d.ts +30 -0
  31. package/dist/api/sonamu.types.d.ts.map +1 -0
  32. package/dist/api/sonamu.types.js +2 -0
  33. package/dist/api/sonamu.types.js.map +1 -0
  34. package/dist/bin/build-config.d.ts +5 -0
  35. package/dist/bin/build-config.d.ts.map +1 -0
  36. package/dist/bin/build-config.js +2 -0
  37. package/dist/bin/build-config.js.map +1 -0
  38. package/dist/bin/cli-wrapper.d.ts +2 -0
  39. package/dist/bin/cli-wrapper.d.ts.map +1 -0
  40. package/dist/bin/cli-wrapper.js +1 -38
  41. package/dist/bin/cli-wrapper.js.map +1 -1
  42. package/dist/bin/cli.d.ts +2 -2
  43. package/dist/bin/cli.d.ts.map +1 -0
  44. package/dist/bin/cli.js +1 -903
  45. package/dist/bin/cli.js.map +1 -1
  46. package/dist/bin/cli.mjs +2 -2
  47. package/dist/{chunk-DMJSNO2L.js → chunk-2WAC2GER.js} +44 -44
  48. package/dist/{chunk-DMJSNO2L.js.map → chunk-2WAC2GER.js.map} +1 -1
  49. package/dist/{chunk-NI37CY4T.mjs → chunk-C3IPIF6O.mjs} +2 -2
  50. package/dist/{chunk-DYFCACHD.js → chunk-EXHKSVTE.js} +7 -7
  51. package/dist/{chunk-QJFHDCBN.mjs → chunk-FCERKIIF.mjs} +2 -2
  52. package/dist/chunk-FCERKIIF.mjs.map +1 -0
  53. package/dist/{chunk-DDJ7T4MA.mjs → chunk-HGIBJYOU.mjs} +2 -2
  54. package/dist/{chunk-NIFOTHBW.mjs → chunk-JKSOJRQA.mjs} +2 -2
  55. package/dist/{chunk-CXAVBVKC.js → chunk-OTKKFP3Y.js} +100 -100
  56. package/dist/{chunk-J6S43O7G.js → chunk-UZ2IY5VE.js} +4 -4
  57. package/dist/database/_batch_update.d.ts +15 -0
  58. package/dist/database/_batch_update.d.ts.map +1 -0
  59. package/dist/database/_batch_update.js +2 -0
  60. package/dist/database/_batch_update.js.map +1 -0
  61. package/dist/database/base-model.d.ts +41 -0
  62. package/dist/database/base-model.d.ts.map +1 -0
  63. package/dist/database/base-model.js +2 -0
  64. package/dist/database/base-model.js.map +1 -0
  65. package/dist/database/code-generator.d.ts +13 -0
  66. package/dist/database/code-generator.d.ts.map +1 -0
  67. package/dist/database/code-generator.js +2 -0
  68. package/dist/database/code-generator.js.map +1 -0
  69. package/dist/database/db.d.ts +40 -0
  70. package/dist/database/db.d.ts.map +1 -0
  71. package/dist/database/db.js +2 -0
  72. package/dist/database/db.js.map +1 -0
  73. package/dist/database/drivers/knex/base-model.js +8 -8
  74. package/dist/database/drivers/knex/base-model.mjs +3 -3
  75. package/dist/database/drivers/kysely/base-model.js +9 -9
  76. package/dist/database/drivers/kysely/base-model.mjs +3 -3
  77. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +2 -0
  78. package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +1 -0
  79. package/dist/database/knex-plugins/knex-on-duplicate-update.js +2 -0
  80. package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +1 -0
  81. package/dist/database/puri-wrapper.d.ts +34 -0
  82. package/dist/database/puri-wrapper.d.ts.map +1 -0
  83. package/dist/database/puri-wrapper.js +2 -0
  84. package/dist/database/puri-wrapper.js.map +1 -0
  85. package/dist/database/puri.d.ts +83 -0
  86. package/dist/database/puri.d.ts.map +1 -0
  87. package/dist/database/puri.js +2 -0
  88. package/dist/database/puri.js.map +1 -0
  89. package/dist/database/puri.types.d.ts +60 -0
  90. package/dist/database/puri.types.d.ts.map +1 -0
  91. package/dist/database/puri.types.js +2 -0
  92. package/dist/database/puri.types.js.map +1 -0
  93. package/dist/database/transaction-context.d.ts +9 -0
  94. package/dist/database/transaction-context.d.ts.map +1 -0
  95. package/dist/database/transaction-context.js +2 -0
  96. package/dist/database/transaction-context.js.map +1 -0
  97. package/dist/database/types.d.ts +39 -0
  98. package/dist/database/types.d.ts.map +1 -0
  99. package/dist/database/types.js +2 -0
  100. package/dist/database/types.js.map +1 -0
  101. package/dist/database/upsert-builder.d.ts +34 -0
  102. package/dist/database/upsert-builder.d.ts.map +1 -0
  103. package/dist/database/upsert-builder.js +2 -0
  104. package/dist/database/upsert-builder.js.map +1 -0
  105. package/dist/entity/entity-manager.d.ts +32 -0
  106. package/dist/entity/entity-manager.d.ts.map +1 -0
  107. package/dist/entity/entity-manager.js +2 -0
  108. package/dist/entity/entity-manager.js.map +1 -0
  109. package/dist/entity/entity-utils.d.ts +61 -0
  110. package/dist/entity/entity-utils.d.ts.map +1 -0
  111. package/dist/entity/entity-utils.js +2 -0
  112. package/dist/entity/entity-utils.js.map +1 -0
  113. package/dist/entity/entity.d.ts +62 -0
  114. package/dist/entity/entity.d.ts.map +1 -0
  115. package/dist/entity/entity.js +2 -0
  116. package/dist/entity/entity.js.map +1 -0
  117. package/dist/entity/migrator.d.ts +135 -0
  118. package/dist/entity/migrator.d.ts.map +1 -0
  119. package/dist/entity/migrator.js +2 -0
  120. package/dist/entity/migrator.js.map +1 -0
  121. package/dist/exceptions/error-handler.d.ts +3 -0
  122. package/dist/exceptions/error-handler.d.ts.map +1 -0
  123. package/dist/exceptions/error-handler.js +2 -0
  124. package/dist/exceptions/error-handler.js.map +1 -0
  125. package/dist/exceptions/so-exceptions.d.ts +48 -0
  126. package/dist/exceptions/so-exceptions.d.ts.map +1 -0
  127. package/dist/exceptions/so-exceptions.js +2 -0
  128. package/dist/exceptions/so-exceptions.js.map +1 -0
  129. package/dist/file-storage/driver.d.ts +45 -0
  130. package/dist/file-storage/driver.d.ts.map +1 -0
  131. package/dist/file-storage/driver.js +2 -0
  132. package/dist/file-storage/driver.js.map +1 -0
  133. package/dist/file-storage/file-storage.d.ts +50 -0
  134. package/dist/file-storage/file-storage.d.ts.map +1 -0
  135. package/dist/file-storage/file-storage.js +2 -0
  136. package/dist/file-storage/file-storage.js.map +1 -0
  137. package/dist/index.d.ts +22 -813
  138. package/dist/index.d.ts.map +1 -0
  139. package/dist/index.js +1 -433
  140. package/dist/index.js.map +1 -1
  141. package/dist/index.mjs +3 -3
  142. package/dist/migration/code-generation.d.ts +15 -0
  143. package/dist/migration/code-generation.d.ts.map +1 -0
  144. package/dist/migration/code-generation.js +2 -0
  145. package/dist/migration/code-generation.js.map +1 -0
  146. package/dist/migration/migration-set.d.ts +17 -0
  147. package/dist/migration/migration-set.d.ts.map +1 -0
  148. package/dist/migration/migration-set.js +2 -0
  149. package/dist/migration/migration-set.js.map +1 -0
  150. package/dist/migration/migrator.d.ts +130 -0
  151. package/dist/migration/migrator.d.ts.map +1 -0
  152. package/dist/migration/migrator.js +2 -0
  153. package/dist/migration/migrator.js.map +1 -0
  154. package/dist/migration/types.d.ts +52 -0
  155. package/dist/migration/types.d.ts.map +1 -0
  156. package/dist/migration/types.js +2 -0
  157. package/dist/migration/types.js.map +1 -0
  158. package/dist/smd/smd-manager.d.ts +28 -0
  159. package/dist/smd/smd-manager.d.ts.map +1 -0
  160. package/dist/smd/smd-manager.js +2 -0
  161. package/dist/smd/smd-manager.js.map +1 -0
  162. package/dist/smd/smd.d.ts +40 -0
  163. package/dist/smd/smd.d.ts.map +1 -0
  164. package/dist/smd/smd.js +2 -0
  165. package/dist/smd/smd.js.map +1 -0
  166. package/dist/syncer/index.d.ts +2 -0
  167. package/dist/syncer/index.d.ts.map +1 -0
  168. package/dist/syncer/index.js +2 -0
  169. package/dist/syncer/index.js.map +1 -0
  170. package/dist/syncer/syncer.d.ts +127 -0
  171. package/dist/syncer/syncer.d.ts.map +1 -0
  172. package/dist/syncer/syncer.js +2 -0
  173. package/dist/syncer/syncer.js.map +1 -0
  174. package/dist/templates/base-template.d.ts +13 -0
  175. package/dist/templates/base-template.d.ts.map +1 -0
  176. package/dist/templates/base-template.js +2 -0
  177. package/dist/templates/base-template.js.map +1 -0
  178. package/dist/templates/entity.template.d.ts +17 -0
  179. package/dist/templates/entity.template.d.ts.map +1 -0
  180. package/dist/templates/entity.template.js +2 -0
  181. package/dist/templates/entity.template.js.map +1 -0
  182. package/dist/templates/generated.template.d.ts +27 -0
  183. package/dist/templates/generated.template.d.ts.map +1 -0
  184. package/dist/templates/generated.template.js +2 -0
  185. package/dist/templates/generated.template.js.map +1 -0
  186. package/dist/templates/generated_http.template.d.ts +24 -0
  187. package/dist/templates/generated_http.template.d.ts.map +1 -0
  188. package/dist/templates/generated_http.template.js +2 -0
  189. package/dist/templates/generated_http.template.js.map +1 -0
  190. package/dist/templates/generated_sso.template.d.ts +20 -0
  191. package/dist/templates/generated_sso.template.d.ts.map +1 -0
  192. package/dist/templates/generated_sso.template.js +2 -0
  193. package/dist/templates/generated_sso.template.js.map +1 -0
  194. package/dist/templates/index.d.ts +2 -0
  195. package/dist/templates/index.d.ts.map +1 -0
  196. package/dist/templates/index.js +2 -0
  197. package/dist/templates/index.js.map +1 -0
  198. package/dist/templates/init_types.template.d.ts +17 -0
  199. package/dist/templates/init_types.template.d.ts.map +1 -0
  200. package/dist/templates/init_types.template.js +2 -0
  201. package/dist/templates/init_types.template.js.map +1 -0
  202. package/dist/templates/model.template.d.ts +17 -0
  203. package/dist/templates/model.template.d.ts.map +1 -0
  204. package/dist/templates/model.template.js +2 -0
  205. package/dist/templates/model.template.js.map +1 -0
  206. package/dist/templates/model_test.template.d.ts +17 -0
  207. package/dist/templates/model_test.template.d.ts.map +1 -0
  208. package/dist/templates/model_test.template.js +2 -0
  209. package/dist/templates/model_test.template.js.map +1 -0
  210. package/dist/templates/service.template.d.ts +29 -0
  211. package/dist/templates/service.template.d.ts.map +1 -0
  212. package/dist/templates/service.template.js +2 -0
  213. package/dist/templates/service.template.js.map +1 -0
  214. package/dist/templates/view_enums_buttonset.template.d.ts +17 -0
  215. package/dist/templates/view_enums_buttonset.template.d.ts.map +1 -0
  216. package/dist/templates/view_enums_buttonset.template.js +2 -0
  217. package/dist/templates/view_enums_buttonset.template.js.map +1 -0
  218. package/dist/templates/view_enums_dropdown.template.d.ts +18 -0
  219. package/dist/templates/view_enums_dropdown.template.d.ts.map +1 -0
  220. package/dist/templates/view_enums_dropdown.template.js +2 -0
  221. package/dist/templates/view_enums_dropdown.template.js.map +1 -0
  222. package/dist/templates/view_enums_select.template.d.ts +17 -0
  223. package/dist/templates/view_enums_select.template.d.ts.map +1 -0
  224. package/dist/templates/view_enums_select.template.js +2 -0
  225. package/dist/templates/view_enums_select.template.js.map +1 -0
  226. package/dist/templates/view_form.template.d.ts +26 -0
  227. package/dist/templates/view_form.template.d.ts.map +1 -0
  228. package/dist/templates/view_form.template.js +2 -0
  229. package/dist/templates/view_form.template.js.map +1 -0
  230. package/dist/templates/view_id_all_select.template.d.ts +17 -0
  231. package/dist/templates/view_id_all_select.template.d.ts.map +1 -0
  232. package/dist/templates/view_id_all_select.template.js +2 -0
  233. package/dist/templates/view_id_all_select.template.js.map +1 -0
  234. package/dist/templates/view_id_async_select.template.d.ts +17 -0
  235. package/dist/templates/view_id_async_select.template.d.ts.map +1 -0
  236. package/dist/templates/view_id_async_select.template.js +2 -0
  237. package/dist/templates/view_id_async_select.template.js.map +1 -0
  238. package/dist/templates/view_list.template.d.ts +38 -0
  239. package/dist/templates/view_list.template.d.ts.map +1 -0
  240. package/dist/templates/view_list.template.js +2 -0
  241. package/dist/templates/view_list.template.js.map +1 -0
  242. package/dist/templates/view_list_columns.template.d.ts +17 -0
  243. package/dist/templates/view_list_columns.template.d.ts.map +1 -0
  244. package/dist/templates/view_list_columns.template.js +2 -0
  245. package/dist/templates/view_list_columns.template.js.map +1 -0
  246. package/dist/templates/view_search_input.template.d.ts +17 -0
  247. package/dist/templates/view_search_input.template.d.ts.map +1 -0
  248. package/dist/templates/view_search_input.template.js +2 -0
  249. package/dist/templates/view_search_input.template.js.map +1 -0
  250. package/dist/testing/_relation-graph.d.ts +7 -0
  251. package/dist/testing/_relation-graph.d.ts.map +1 -0
  252. package/dist/testing/_relation-graph.js +2 -0
  253. package/dist/testing/_relation-graph.js.map +1 -0
  254. package/dist/testing/fixture-manager.d.ts +35 -0
  255. package/dist/testing/fixture-manager.d.ts.map +1 -0
  256. package/dist/testing/fixture-manager.js +2 -0
  257. package/dist/testing/fixture-manager.js.map +1 -0
  258. package/dist/types/types.d.ts +609 -0
  259. package/dist/types/types.d.ts.map +1 -0
  260. package/dist/types/types.js +2 -0
  261. package/dist/types/types.js.map +1 -0
  262. package/dist/typings/knex.d.js +2 -0
  263. package/dist/typings/knex.d.js.map +1 -0
  264. package/dist/utils/async-utils.d.ts +25 -0
  265. package/dist/utils/async-utils.d.ts.map +1 -0
  266. package/dist/utils/async-utils.js +2 -0
  267. package/dist/utils/async-utils.js.map +1 -0
  268. package/dist/utils/controller.d.ts +9 -0
  269. package/dist/utils/controller.d.ts.map +1 -0
  270. package/dist/utils/controller.js +2 -0
  271. package/dist/utils/controller.js.map +1 -0
  272. package/dist/utils/fs-utils.d.ts +9 -0
  273. package/dist/utils/fs-utils.d.ts.map +1 -0
  274. package/dist/utils/fs-utils.js +2 -0
  275. package/dist/utils/fs-utils.js.map +1 -0
  276. package/dist/utils/lodash-able.d.ts +2 -0
  277. package/dist/utils/lodash-able.d.ts.map +1 -0
  278. package/dist/utils/lodash-able.js +2 -0
  279. package/dist/utils/lodash-able.js.map +1 -0
  280. package/dist/utils/model.d.ts +17 -0
  281. package/dist/utils/model.d.ts.map +1 -0
  282. package/dist/utils/model.js +2 -0
  283. package/dist/utils/model.js.map +1 -0
  284. package/dist/utils/sql-parser.d.ts +4 -0
  285. package/dist/utils/sql-parser.d.ts.map +1 -0
  286. package/dist/utils/sql-parser.js +2 -0
  287. package/dist/utils/sql-parser.js.map +1 -0
  288. package/dist/utils/utils.d.ts +9 -0
  289. package/dist/utils/utils.d.ts.map +1 -0
  290. package/dist/utils/utils.js +2 -0
  291. package/dist/utils/utils.js.map +1 -0
  292. package/dist/utils/zod-error.d.ts +8 -0
  293. package/dist/utils/zod-error.d.ts.map +1 -0
  294. package/dist/utils/zod-error.js +2 -0
  295. package/dist/utils/zod-error.js.map +1 -0
  296. package/nodemon.json +6 -0
  297. package/package.json +29 -44
  298. package/src/api/base-frame.ts +3 -4
  299. package/src/api/caster.ts +22 -23
  300. package/src/api/code-converters.ts +170 -134
  301. package/src/api/context.ts +13 -6
  302. package/src/api/decorators.ts +146 -20
  303. package/src/api/index.ts +2 -0
  304. package/src/api/sonamu.ts +374 -165
  305. package/src/bin/build-config.ts +5 -0
  306. package/src/bin/cli-wrapper.ts +29 -40
  307. package/src/bin/cli.ts +132 -190
  308. package/src/database/_batch_update.ts +10 -15
  309. package/src/database/base-model.ts +300 -216
  310. package/src/database/db.ts +191 -21
  311. package/src/database/{drivers/knex/plugins → knex-plugins}/knex-on-duplicate-update.ts +1 -1
  312. package/src/database/puri-wrapper.ts +129 -0
  313. package/src/database/puri.ts +808 -0
  314. package/src/database/puri.types.ts +222 -0
  315. package/src/database/transaction-context.ts +18 -0
  316. package/src/database/upsert-builder.ts +32 -35
  317. package/src/entity/entity-manager.ts +7 -15
  318. package/src/entity/entity.ts +9 -31
  319. package/src/entity/migrator-/354/235/264/354/202/254/352/260/224/354/226/264/354/232/224.md +1 -0
  320. package/src/file-storage/driver.ts +121 -0
  321. package/src/file-storage/file-storage.ts +100 -0
  322. package/src/index.ts +14 -11
  323. package/src/migration/code-generation.ts +777 -0
  324. package/src/migration/migration-set.ts +453 -0
  325. package/src/migration/migrator.ts +823 -0
  326. package/src/migration/types.ts +53 -0
  327. package/src/shared/web.shared.ts.txt +33 -2
  328. package/src/syncer/syncer.ts +294 -127
  329. package/src/templates/generated.template.ts +13 -1
  330. package/src/templates/generated_http.template.ts +15 -12
  331. package/src/templates/generated_sso.template.ts +50 -2
  332. package/src/templates/model.template.ts +138 -2
  333. package/src/templates/service.template.ts +0 -1
  334. package/src/templates/view_form.template.ts +11 -7
  335. package/src/templates/view_list.template.ts +12 -4
  336. package/src/testing/fixture-manager.ts +229 -174
  337. package/src/types/types.ts +102 -14
  338. package/src/utils/async-utils.ts +64 -0
  339. package/src/utils/fs-utils.ts +17 -0
  340. package/src/utils/model.ts +0 -2
  341. package/src/utils/utils.ts +14 -58
  342. package/src/utils/zod-error.ts +12 -176
  343. package/tsconfig.json +2 -0
  344. package/tsup.config.js +4 -2
  345. package/.pnp.cjs +0 -14363
  346. package/.pnp.loader.mjs +0 -2047
  347. package/.vscode/extensions.json +0 -6
  348. package/.vscode/settings.json +0 -9
  349. package/.yarnrc.yml +0 -5
  350. package/dist/chunk-QJFHDCBN.mjs.map +0 -1
  351. package/src/database/base-model.abstract.ts +0 -97
  352. package/src/database/db.abstract.ts +0 -75
  353. package/src/database/drivers/knex/base-model.ts +0 -55
  354. package/src/database/drivers/knex/client.ts +0 -209
  355. package/src/database/drivers/knex/db.ts +0 -232
  356. package/src/database/drivers/knex/generator.ts +0 -659
  357. package/src/database/drivers/kysely/base-model.ts +0 -89
  358. package/src/database/drivers/kysely/client.ts +0 -309
  359. package/src/database/drivers/kysely/db.ts +0 -238
  360. package/src/database/drivers/kysely/generator.ts +0 -714
  361. package/src/database/types.ts +0 -118
  362. package/src/entity/migrator.ts +0 -1400
  363. package/src/smd/smd-manager.ts +0 -139
  364. package/src/smd/smd.ts +0 -571
  365. package/src/templates/kysely_types.template.ts +0 -205
  366. /package/dist/{chunk-NI37CY4T.mjs.map → chunk-C3IPIF6O.mjs.map} +0 -0
  367. /package/dist/{chunk-DYFCACHD.js.map → chunk-EXHKSVTE.js.map} +0 -0
  368. /package/dist/{chunk-DDJ7T4MA.mjs.map → chunk-HGIBJYOU.mjs.map} +0 -0
  369. /package/dist/{chunk-NIFOTHBW.mjs.map → chunk-JKSOJRQA.mjs.map} +0 -0
  370. /package/dist/{chunk-CXAVBVKC.js.map → chunk-OTKKFP3Y.js.map} +0 -0
  371. /package/dist/{chunk-J6S43O7G.js.map → chunk-UZ2IY5VE.js.map} +0 -0
@@ -1,15 +1,19 @@
1
1
  import path, { dirname } from "path";
2
2
  import { globAsync, importMultiple } from "../utils/utils";
3
- import fs from "fs-extra";
3
+ import { createReadStream } from "fs";
4
+ import { mkdir, readFile, rm, writeFile } from "fs/promises";
5
+ import { exists } from "../utils/fs-utils";
4
6
  import crypto from "crypto";
5
7
  import equal from "fast-deep-equal";
6
- import _ from "lodash";
8
+ import _, { chunk } from "lodash";
7
9
  import inflection from "inflection";
8
10
  import { EntityManager, EntityNamesRecord } from "../entity/entity-manager";
9
11
  import ts from "typescript";
10
12
  import {
11
13
  ApiParam,
12
14
  ApiParamType,
15
+ EntityProp,
16
+ EntityPropNode,
13
17
  isBelongsToOneRelationProp,
14
18
  isBigIntegerProp,
15
19
  isBooleanProp,
@@ -29,9 +33,6 @@ import {
29
33
  isTimestampProp,
30
34
  isUuidProp,
31
35
  isVirtualProp,
32
- EntityProp,
33
- EntityPropNode,
34
- SQLDateTimeString,
35
36
  } from "../types/types";
36
37
  import {
37
38
  ApiDecoratorOptions,
@@ -73,11 +74,17 @@ import { Template__view_search_input } from "../templates/view_search_input.temp
73
74
  import { Template__view_list_columns } from "../templates/view_list_columns.template";
74
75
  import { Template__generated_http } from "../templates/generated_http.template";
75
76
  import { Sonamu } from "../api/sonamu";
76
- import { execSync } from "child_process";
77
77
  import { Template__generated_sso } from "../templates/generated_sso.template";
78
- import { Template__kysely_interface } from "../templates/kysely_types.template";
79
- import { DB } from "../database/db";
80
78
  import { setTimeout as setTimeoutPromises } from "timers/promises";
79
+ import assert from "assert";
80
+ import * as swc from "@swc/core";
81
+ import { minimatch } from "minimatch";
82
+ import {
83
+ everyAsync,
84
+ filterAsync,
85
+ mapAsync,
86
+ reduceAsync,
87
+ } from "../utils/async-utils";
81
88
 
82
89
  type FileType =
83
90
  | "model"
@@ -122,8 +129,19 @@ export class Syncer {
122
129
  models: { [modelName: string]: unknown } = {};
123
130
  isSyncing: boolean = false;
124
131
 
132
+ public checksumPatternGroup: GlobPattern = {
133
+ /* 원본 체크 */
134
+ entity: Sonamu.apiRootPath + "/src/application/**/*.entity.json",
135
+ types: Sonamu.apiRootPath + "/src/application/**/*.types.ts",
136
+ generated: Sonamu.apiRootPath + "/src/application/sonamu.generated.ts",
137
+ functions: Sonamu.apiRootPath + "/src/application/**/*.functions.ts",
138
+ /* compiled-JS 체크 */
139
+ model: Sonamu.apiRootPath + "/dist/application/**/*.model.js",
140
+ frame: Sonamu.apiRootPath + "/dist/application/**/*.frame.js",
141
+ };
142
+
125
143
  get checksumsPath(): string {
126
- return path.join(Sonamu.apiRootPath, "/.so-checksum");
144
+ return path.join(Sonamu.apiRootPath, "/sonamu.lock");
127
145
  }
128
146
  public constructor() {}
129
147
 
@@ -141,7 +159,7 @@ export class Syncer {
141
159
  const srcCodePath = path
142
160
  .join(currentDirname, `../shared/${target}.shared.ts.txt`)
143
161
  .replace("/dist/", "/src/");
144
- if (!fs.existsSync(srcCodePath)) {
162
+ if (!(await exists(srcCodePath))) {
145
163
  return;
146
164
  }
147
165
 
@@ -153,7 +171,7 @@ export class Syncer {
153
171
 
154
172
  const srcChecksum = await this.getChecksumOfFile(srcCodePath);
155
173
  const dstChecksum = await (async () => {
156
- if (fs.existsSync(dstCodePath) === false) {
174
+ if (!(await exists(dstCodePath))) {
157
175
  return "";
158
176
  }
159
177
  return this.getChecksumOfFile(dstCodePath);
@@ -162,7 +180,7 @@ export class Syncer {
162
180
  if (srcChecksum === dstChecksum) {
163
181
  return;
164
182
  }
165
- fs.writeFileSync(dstCodePath, fs.readFileSync(srcCodePath));
183
+ await writeFile(dstCodePath, await readFile(srcCodePath));
166
184
  console.log(chalk.blue("shared.ts is synced"));
167
185
  })
168
186
  );
@@ -175,7 +193,7 @@ export class Syncer {
175
193
  // 비교
176
194
  const isSame = equal(currentChecksums, previousChecksums);
177
195
  if (isSame) {
178
- const msg = "Every files are synced!";
196
+ const msg = "All files are synced!";
179
197
  const margin = (process.stdout.columns - msg.length) / 2;
180
198
  console.log(
181
199
  chalk.black.bgGreen(" ".repeat(margin) + msg + " ".repeat(margin))
@@ -209,12 +227,35 @@ export class Syncer {
209
227
  const diffFiles = diff.map((r) => r.path);
210
228
  console.log("Changed Files: ", diffFiles);
211
229
 
230
+ const { changedChecksums } = await this.doSyncActions(
231
+ diffFiles,
232
+ currentChecksums
233
+ );
234
+ // checksum 오버라이드 (액션 실행 과정 중간에 체크섬이 바뀐 경우)
235
+ currentChecksums = changedChecksums ?? currentChecksums;
236
+
237
+ // 저장
238
+ await this.saveChecksums(currentChecksums);
239
+
240
+ // 싱크 종료
241
+ this.isSyncing = false;
242
+ abc.abort();
243
+ process.off("SIGUSR2", onSIGUSR2);
244
+ }
245
+
246
+ async doSyncActions(
247
+ diffFiles: string[],
248
+ currentChecksums?: PathAndChecksum[]
249
+ ): Promise<{
250
+ diffTypes: string[];
251
+ changedChecksums?: PathAndChecksum[];
252
+ }> {
212
253
  // 다른 부분 찾아 액션
213
254
  const diffGroups = _.groupBy(diffFiles, (r) => {
214
255
  const matched = r.match(
215
256
  /\.(model|types|functions|entity|generated|frame)\.[tj]s/
216
257
  );
217
- return matched![1];
258
+ return matched?.[1] ?? "unknown";
218
259
  }) as unknown as DiffGroups;
219
260
 
220
261
  // 변경된 파일들을 타입별로 분리하여 각 타입별 액션 처리
@@ -223,19 +264,24 @@ export class Syncer {
223
264
  // 트리거: entity, types
224
265
  // 액션: 스키마 생성
225
266
  if (diffTypes.includes("entity") || diffTypes.includes("types")) {
226
- console.log("// 액션: 스키마 생성");
267
+ await EntityManager.reload();
268
+
227
269
  await this.actionGenerateSchemas();
228
270
 
229
- if (
230
- DB.baseConfig?.client === "kysely" &&
231
- DB.baseConfig.types?.enabled !== false
232
- ) {
233
- console.log("// 액션: kysely 인터페이스 생성");
234
- await this.generateTemplate(
235
- "kysely_interface",
236
- {},
237
- { overwrite: true }
271
+ // types 생성(entity 새로 추가된 경우)
272
+ // parentId가 없고, types가 없는 경우에만 생성
273
+ const entityId = this.getEntityIdFromPath([
274
+ ...(diffGroups["entity"] ?? []),
275
+ ])[0];
276
+ if (entityId) {
277
+ const entity = EntityManager.get(entityId);
278
+ const typeFilePath = path.join(
279
+ Sonamu.apiRootPath,
280
+ `src/application/${entity.names.fs}/${entity.names.fs}.types.ts`
238
281
  );
282
+ if (entity.parentId === undefined && !(await exists(typeFilePath))) {
283
+ await this.generateTemplate("init_types", { entityId });
284
+ }
239
285
  }
240
286
 
241
287
  // generated 싱크까지 동시에 처리 후 체크섬 갱신
@@ -244,7 +290,11 @@ export class Syncer {
244
290
  "/src/application/sonamu.generated.ts",
245
291
  ]);
246
292
  diffTypes.push("generated");
247
- currentChecksums = await this.getCurrentChecksums();
293
+
294
+ // fullSync인 경우만 실행
295
+ if (currentChecksums) {
296
+ currentChecksums = await this.getCurrentChecksums();
297
+ }
248
298
  }
249
299
 
250
300
  // 트리거: types, enums, generated 변경시
@@ -254,8 +304,6 @@ export class Syncer {
254
304
  diffTypes.includes("functions") ||
255
305
  diffTypes.includes("generated")
256
306
  ) {
257
- console.log("// 액션: 파일 싱크 types / functions / generated");
258
-
259
307
  const tsPaths = _.uniq(
260
308
  [
261
309
  ...(diffGroups["types"] ?? []),
@@ -268,15 +316,22 @@ export class Syncer {
268
316
 
269
317
  // 트리거: model
270
318
  if (diffTypes.includes("model") || diffTypes.includes("frame")) {
271
- console.log("// 액션: 서비스 생성");
272
319
  const mergedGroup = [
273
320
  ...(diffGroups["model"] ?? []),
274
321
  ...(diffGroups["frame"] ?? []),
275
322
  ];
323
+
324
+ // registeredApis 초기화
325
+ await this.autoloadModels();
326
+
327
+ // Syncer.apis 초기화
328
+ await this.autoloadApis();
329
+
276
330
  const params: { namesRecord: EntityNamesRecord; modelTsPath: string }[] =
277
331
  mergedGroup.map((modelPath) => {
278
332
  if (modelPath.endsWith(".model.js")) {
279
333
  const entityId = this.getEntityIdFromPath([modelPath])[0];
334
+ assert(entityId);
280
335
  return {
281
336
  namesRecord: EntityManager.getNamesFromId(entityId),
282
337
  modelTsPath: path.join(
@@ -289,6 +344,7 @@ export class Syncer {
289
344
  }
290
345
  if (modelPath.endsWith("frame.js")) {
291
346
  const [, frameName] = modelPath.match(/.+\/(.+)\.frame.js$/) ?? [];
347
+ assert(frameName);
292
348
  return {
293
349
  namesRecord: EntityManager.getNamesFromId(frameName),
294
350
  modelTsPath: path.join(
@@ -303,24 +359,122 @@ export class Syncer {
303
359
  });
304
360
  await this.actionGenerateServices(params);
305
361
 
306
- console.log("// 액션: HTTP파일 생성");
307
362
  await this.actionGenerateHttps();
308
363
  }
309
364
 
310
- // 저장
311
- await this.saveChecksums(currentChecksums);
365
+ return {
366
+ diffTypes,
367
+ changedChecksums: currentChecksums,
368
+ };
369
+ }
312
370
 
313
- // 싱크 종료
314
- this.isSyncing = false;
315
- abc.abort();
316
- process.off("SIGUSR2", onSIGUSR2);
371
+ async syncFromWatcher(diffFiles: string[]): Promise<void> {
372
+ const tsFiles = diffFiles.filter((file) => file.endsWith(".ts"));
373
+ const jsonFiles = diffFiles.filter((file) => file.endsWith(".json"));
374
+
375
+ // transpile (성능 이슈를 고려하여 5개 동시 실행)
376
+ const chunks = chunk(tsFiles, 5);
377
+ let transpiledFilePaths: string[] = [];
378
+ for (const chunk of chunks) {
379
+ const _transpiledFilePaths = await Promise.all(
380
+ chunk.map(async (diffFile) => {
381
+ const { code, map } = await swc.transformFile(diffFile, {
382
+ module: {
383
+ type: "commonjs",
384
+ },
385
+ jsc: {
386
+ parser: {
387
+ syntax: "typescript",
388
+ decorators: true,
389
+ },
390
+ target: "es5",
391
+ },
392
+ sourceMaps: true,
393
+ });
394
+
395
+ const jsPath = diffFile
396
+ .replace("/src/", "/dist/")
397
+ .replace(".ts", ".js");
398
+ await mkdir(path.dirname(jsPath), { recursive: true }); // 파일 새로 추가된 경우 디렉토리 생성
399
+ await writeFile(jsPath, code);
400
+
401
+ if (map) {
402
+ const mapPath = jsPath + ".map";
403
+ await mkdir(path.dirname(mapPath), { recursive: true });
404
+ await writeFile(mapPath, map);
405
+
406
+ const sourceMapComment =
407
+ "\n//# sourceMappingURL=" + path.basename(mapPath);
408
+ await writeFile(jsPath, sourceMapComment, {
409
+ flag: "a" /*파일 끝에 붙이기만 해요*/,
410
+ });
411
+ }
412
+
413
+ console.log(
414
+ chalk.bold("Transpiled: ") +
415
+ chalk.blue(`${jsPath.replace(Sonamu.apiRootPath, "api")}`)
416
+ );
417
+ return jsPath;
418
+ })
419
+ );
420
+ transpiledFilePaths.push(..._transpiledFilePaths);
421
+ }
422
+
423
+ // module reload - doSyncActions 전에 캐시 삭제
424
+ function clearModuleAndDependents(filePath: string) {
425
+ const resolved = require.resolve(filePath);
426
+ const toDelete = new Set([resolved]);
427
+
428
+ // 이 파일을 children으로 가진 모듈 찾기
429
+ Object.keys(require.cache).forEach((key) => {
430
+ const mod = require.cache[key];
431
+ if (mod?.children?.some((child) => child.id === resolved)) {
432
+ toDelete.add(key);
433
+ }
434
+ });
435
+
436
+ toDelete.forEach((key) => {
437
+ if (key.includes("dist/index.js")) {
438
+ process.kill(process.pid, "SIGUSR2");
439
+ }
440
+ delete require.cache[key];
441
+ // console.debug(
442
+ // chalk.bold("ModuleCleared: ") +
443
+ // chalk.blue(`${key.replace(Sonamu.apiRootPath, "api")}`)
444
+ // );
445
+ });
446
+ }
447
+ transpiledFilePaths.map((filePath) => {
448
+ clearModuleAndDependents(filePath);
449
+ });
450
+
451
+ // doSyncActions
452
+ const allFilePaths = [...tsFiles, ...transpiledFilePaths, ...jsonFiles];
453
+ const targetFilePaths = allFilePaths
454
+ .filter((filePath) => {
455
+ return Object.values(this.checksumPatternGroup).some((pattern) =>
456
+ minimatch(filePath, pattern)
457
+ );
458
+ })
459
+ .map((filePath) => "/" + path.relative(Sonamu.apiRootPath, filePath));
460
+ await this.doSyncActions(targetFilePaths);
461
+
462
+ this.apis = [];
463
+ this.types = {};
464
+ this.models = {};
465
+ await this.autoloadTypes();
466
+ await this.autoloadModels();
467
+ await this.autoloadApis();
468
+
469
+ this.syncUI();
317
470
  }
318
471
 
319
472
  getEntityIdFromPath(filePaths: string[]): string[] {
320
473
  return _.uniq(
321
474
  filePaths.map((p) => {
322
475
  const matched = p.match(/application\/(.+)\//);
323
- return inflection.camelize(matched![1].replace(/\-/g, "_"));
476
+ assert(matched && matched[1]);
477
+ return inflection.camelize(matched[1].replace(/\-/g, "_"));
324
478
  })
325
479
  );
326
480
  }
@@ -361,15 +515,16 @@ export class Syncer {
361
515
  {},
362
516
  { overwrite: true }
363
517
  );
518
+ assert(res);
364
519
  return res;
365
520
  }
366
521
 
367
522
  async copyFileWithReplaceCoreToShared(fromPath: string, toPath: string) {
368
- if (!fs.existsSync(fromPath)) {
523
+ if (!(await exists(fromPath))) {
369
524
  return;
370
525
  }
371
526
 
372
- const oldFileContent = fs.readFileSync(fromPath).toString();
527
+ const oldFileContent = (await readFile(fromPath)).toString();
373
528
 
374
529
  const newFileContent = (() => {
375
530
  const nfc = oldFileContent.replace(
@@ -383,13 +538,12 @@ export class Syncer {
383
538
  return nfc;
384
539
  }
385
540
  })();
386
- return fs.writeFile(toPath, newFileContent);
541
+ return writeFile(toPath, newFileContent);
387
542
  }
388
543
 
389
544
  async actionSyncFilesToTargets(tsPaths: string[]): Promise<string[]> {
390
545
  const { targets } = Sonamu.config.sync;
391
546
  const { dir: apiDir } = Sonamu.config.api;
392
- const { appRootPath } = Sonamu;
393
547
 
394
548
  return (
395
549
  await Promise.all(
@@ -401,12 +555,14 @@ export class Syncer {
401
555
  .replace(`/${apiDir}/`, `/${target}/`)
402
556
  .replace("/application/", "/services/");
403
557
  const dir = dirname(dst);
404
- if (!fs.existsSync(dir)) {
405
- fs.mkdirSync(dir, { recursive: true });
558
+ if (!(await exists(dir))) {
559
+ await mkdir(dir, { recursive: true });
406
560
  }
407
561
  console.log(
408
- "COPIED ",
409
- chalk.blue(dst.replace(appRootPath + "/", ""))
562
+ chalk.bold("Copied: ") +
563
+ chalk.blue(
564
+ `Copied: ${dst.replace(Sonamu.appRootPath + "/", "")}`
565
+ )
410
566
  );
411
567
  await this.copyFileWithReplaceCoreToShared(realSrc, dst);
412
568
  return dst;
@@ -418,22 +574,13 @@ export class Syncer {
418
574
  }
419
575
 
420
576
  async getCurrentChecksums(): Promise<PathAndChecksum[]> {
421
- const PatternGroup: GlobPattern = {
422
- /* 원본 체크 */
423
- entity: Sonamu.apiRootPath + "/src/application/**/*.entity.json",
424
- types: Sonamu.apiRootPath + "/src/application/**/*.types.ts",
425
- generated: Sonamu.apiRootPath + "/src/application/sonamu.generated.ts",
426
- functions: Sonamu.apiRootPath + "/src/application/**/*.functions.ts",
427
- /* compiled-JS 체크 */
428
- model: Sonamu.apiRootPath + "/dist/application/**/*.model.js",
429
- frame: Sonamu.apiRootPath + "/dist/application/**/*.frame.js",
430
- };
431
-
432
577
  const filePaths = (
433
578
  await Promise.all(
434
- Object.entries(PatternGroup).map(async ([_fileType, pattern]) => {
435
- return globAsync(pattern);
436
- })
579
+ Object.entries(this.checksumPatternGroup).map(
580
+ async ([_fileType, pattern]) => {
581
+ return globAsync(pattern);
582
+ }
583
+ )
437
584
  )
438
585
  )
439
586
  .flat()
@@ -454,27 +601,29 @@ export class Syncer {
454
601
  }
455
602
 
456
603
  async getPreviousChecksums(): Promise<PathAndChecksum[]> {
457
- if (fs.existsSync(this.checksumsPath) === false) {
604
+ if (!(await exists(this.checksumsPath))) {
458
605
  return [];
459
606
  }
460
607
 
461
- const previousChecksums = (await fs.readJSON(
462
- this.checksumsPath
463
- )) as PathAndChecksum[];
608
+ const previousChecksums = JSON.parse(
609
+ (await readFile(this.checksumsPath, "utf-8"))
610
+ ) as PathAndChecksum[];
464
611
  return previousChecksums;
465
612
  }
466
613
 
467
614
  async saveChecksums(checksums: PathAndChecksum[]): Promise<void> {
468
- await fs.writeJSON(this.checksumsPath, checksums, {
469
- spaces: 2,
470
- });
615
+ await writeFile(
616
+ this.checksumsPath,
617
+ JSON.stringify(checksums, null, 2),
618
+ "utf-8"
619
+ );
471
620
  console.log("checksum saved", this.checksumsPath);
472
621
  }
473
622
 
474
623
  async getChecksumOfFile(filePath: string): Promise<string> {
475
624
  return new Promise<string>((resolve, reject) => {
476
625
  const hash = crypto.createHash("sha1");
477
- const input = fs.createReadStream(filePath);
626
+ const input = createReadStream(filePath);
478
627
  input.on("error", reject);
479
628
  input.on("data", function (chunk: any) {
480
629
  hash.update(chunk);
@@ -488,7 +637,7 @@ export class Syncer {
488
637
  async readApisFromFile(filePath: string) {
489
638
  const sourceFile = ts.createSourceFile(
490
639
  filePath,
491
- fs.readFileSync(filePath).toString(),
640
+ (await readFile(filePath)).toString(),
492
641
  ts.ScriptTarget.Latest
493
642
  );
494
643
 
@@ -647,6 +796,7 @@ export class Syncer {
647
796
  t: "object",
648
797
  props: literalNode.members.map((member) => {
649
798
  if (ts.isIndexSignatureDeclaration(member)) {
799
+ assert(member.parameters[0]);
650
800
  const res = this.resolveParamDec({
651
801
  name: member.parameters[0].name as ts.Identifier,
652
802
  type: member.parameters[0].type as ts.TypeNode,
@@ -791,12 +941,15 @@ export class Syncer {
791
941
  );
792
942
  // console.debug(chalk.yellow(`autoload:models @ ${pathPattern}`));
793
943
 
794
- const filePaths = (await globAsync(pathPattern)).filter((path) => {
795
- // src 디렉터리 내에 있는 해당 파일이 존재할 경우에만 로드
796
- // 삭제된 파일이지만 dist에 남아있는 경우 BaseSchema undefined 에러 방지
797
- const srcPath = path.replace("/dist/", "/src/").replace(".js", ".ts");
798
- return fs.existsSync(srcPath);
799
- });
944
+ const filePaths = await filterAsync(
945
+ await globAsync(pathPattern),
946
+ async (path) => {
947
+ // src 디렉터리 내에 있는 해당 파일이 존재할 경우에만 로드
948
+ // 삭제된 파일이지만 dist에 남아있는 경우 BaseSchema undefined 에러 방지
949
+ const srcPath = path.replace("/dist/", "/src/").replace(".js", ".ts");
950
+ return await exists(srcPath);
951
+ }
952
+ );
800
953
  const modules = await importMultiple(filePaths);
801
954
  const functions = modules
802
955
  .map(({ imported }) => Object.entries(imported))
@@ -822,16 +975,15 @@ export class Syncer {
822
975
  ];
823
976
  // console.debug(chalk.magenta(`autoload:types @ ${pathPatterns.join("\n")}`));
824
977
 
825
- const filePaths = (
826
- await Promise.all(pathPatterns.map((pattern) => globAsync(pattern)))
827
- )
828
- .flat()
829
- .filter((path) => {
978
+ const filePaths = await filterAsync(
979
+ (await mapAsync(pathPatterns, globAsync)).flat(),
980
+ async (path) => {
830
981
  // src 디렉터리 내에 있는 해당 파일이 존재할 경우에만 로드
831
982
  // 삭제된 파일이지만 dist에 남아있는 경우 BaseSchema undefined 에러 방지
832
983
  const srcPath = path.replace("/dist/", "/src/").replace(".js", ".ts");
833
- return fs.existsSync(srcPath);
834
- });
984
+ return await exists(srcPath);
985
+ }
986
+ );
835
987
  const modules = await importMultiple(filePaths, doRefresh);
836
988
  const functions = modules
837
989
  .map(({ imported }) => Object.entries(imported))
@@ -877,8 +1029,6 @@ export class Syncer {
877
1029
  return new Template__view_enums_dropdown();
878
1030
  } else if (key === "view_enums_buttonset") {
879
1031
  return new Template__view_enums_buttonset();
880
- } else if (key === "kysely_interface") {
881
- return new Template__kysely_interface();
882
1032
  } else {
883
1033
  throw new BadRequestException(`잘못된 템플릿 키 ${key}`);
884
1034
  }
@@ -1012,13 +1162,13 @@ export class Syncer {
1012
1162
  return await Promise.all(
1013
1163
  dstFilePaths.map(async (dstFilePath) => {
1014
1164
  const dir = path.dirname(dstFilePath);
1015
- if (fs.existsSync(dir) === false) {
1016
- fs.mkdirSync(dir, { recursive: true });
1165
+ if (!(await exists(dir))) {
1166
+ await mkdir(dir, { recursive: true });
1017
1167
  }
1018
- fs.writeFileSync(dstFilePath, pathAndCode.code);
1168
+ await writeFile(dstFilePath, pathAndCode.code);
1019
1169
  console.log(
1020
- "GENERATED ",
1021
- chalk.blue(dstFilePath.replace(appRootPath + "/", ""))
1170
+ chalk.bold("Generated: ") +
1171
+ chalk.blue(`${dstFilePath.replace(appRootPath + "/", "")}`)
1022
1172
  );
1023
1173
  return dstFilePath;
1024
1174
  })
@@ -1047,18 +1197,19 @@ export class Syncer {
1047
1197
  )
1048
1198
  ).flat();
1049
1199
 
1050
- const filteredPathAndCodes: PathAndCode[] = (() => {
1200
+ const filteredPathAndCodes: PathAndCode[] = await (async () => {
1051
1201
  if (generateOptions.overwrite === true) {
1052
1202
  return pathAndCodes;
1053
1203
  } else {
1054
- return pathAndCodes.filter((pathAndCode) => {
1204
+ return await filterAsync(pathAndCodes, async (pathAndCode) => {
1055
1205
  const { targets } = Sonamu.config.sync;
1056
1206
  const filePath = `${Sonamu.appRootPath}/${pathAndCode.path}`;
1057
1207
  const dstFilePaths = targets.map((target) =>
1058
1208
  filePath.replace("/:target/", `/${target}/`)
1059
1209
  );
1060
- return dstFilePaths.every(
1061
- (dstPath) => fs.existsSync(dstPath) === false
1210
+ return await everyAsync(
1211
+ dstFilePaths,
1212
+ async (dstPath) => !(await exists(dstPath))
1062
1213
  );
1063
1214
  });
1064
1215
  }
@@ -1076,11 +1227,11 @@ export class Syncer {
1076
1227
  );
1077
1228
  }
1078
1229
 
1079
- checkExistsGenCode(
1230
+ async checkExistsGenCode(
1080
1231
  entityId: string,
1081
1232
  templateKey: TemplateKey,
1082
1233
  enumId?: string
1083
- ): { subPath: string; fullPath: string; isExists: boolean } {
1234
+ ): Promise<{ subPath: string; fullPath: string; isExists: boolean }> {
1084
1235
  const { target, path: genPath } = this.getTemplate(
1085
1236
  templateKey
1086
1237
  ).getTargetAndPath(EntityManager.getNamesFromId(entityId), enumId);
@@ -1090,32 +1241,33 @@ export class Syncer {
1090
1241
  return {
1091
1242
  subPath,
1092
1243
  fullPath,
1093
- isExists: fs.existsSync(fullPath),
1244
+ isExists: await exists(fullPath),
1094
1245
  };
1095
1246
  }
1096
1247
 
1097
- checkExists(
1248
+ async checkExists(
1098
1249
  entityId: string,
1099
1250
  enums: {
1100
1251
  [name: string]: z.ZodEnum<any>;
1101
1252
  }
1102
- ): Record<`${TemplateKey}${string}`, boolean> {
1253
+ ): Promise<Record<`${TemplateKey}${string}`, boolean>> {
1103
1254
  const keys: TemplateKey[] = TemplateKey.options;
1104
1255
  const names = EntityManager.getNamesFromId(entityId);
1105
1256
  const enumsKeys = Object.keys(enums).filter(
1106
1257
  (name) => name !== names.constant
1107
1258
  );
1108
1259
 
1109
- return keys.reduce(
1110
- (result, key) => {
1260
+ return await reduceAsync(
1261
+ keys,
1262
+ async (result, key) => {
1111
1263
  const tpl = this.getTemplate(key);
1112
1264
  if (key.startsWith("view_enums")) {
1113
- enumsKeys.map((componentId) => {
1265
+ await mapAsync(enumsKeys, async (componentId) => {
1114
1266
  const { target, path: p } = tpl.getTargetAndPath(
1115
1267
  names,
1116
1268
  componentId
1117
1269
  );
1118
- result[`${key}__${componentId}`] = fs.existsSync(
1270
+ result[`${key}__${componentId}`] = await exists(
1119
1271
  path.join(Sonamu.appRootPath, target, p)
1120
1272
  );
1121
1273
  });
@@ -1125,13 +1277,13 @@ export class Syncer {
1125
1277
  const { target, path: p } = tpl.getTargetAndPath(names);
1126
1278
  const { targets } = Sonamu.config.sync;
1127
1279
  if (target.includes(":target")) {
1128
- targets.map((t) => {
1129
- result[`${key}__${t}`] = fs.existsSync(
1280
+ await mapAsync(targets, async (t) => {
1281
+ result[`${key}__${t}`] = await exists(
1130
1282
  path.join(Sonamu.appRootPath, target.replace(":target", t), p)
1131
1283
  );
1132
1284
  });
1133
1285
  } else {
1134
- result[key] = fs.existsSync(path.join(Sonamu.appRootPath, target, p));
1286
+ result[key] = await exists(path.join(Sonamu.appRootPath, target, p));
1135
1287
  }
1136
1288
 
1137
1289
  return result;
@@ -1221,13 +1373,13 @@ export class Syncer {
1221
1373
  } else if (isTimeProp(prop)) {
1222
1374
  zodType = z.string().length(8);
1223
1375
  } else if (isDateTimeProp(prop)) {
1224
- zodType = SQLDateTimeString;
1376
+ zodType = z.date();
1225
1377
  } else if (isTimestampProp(prop)) {
1226
- zodType = SQLDateTimeString;
1378
+ zodType = z.date();
1227
1379
  } else if (isJsonProp(prop)) {
1228
1380
  zodType = await this.getZodTypeById(prop.id);
1229
1381
  } else if (isUuidProp(prop)) {
1230
- zodType = z.string().uuid();
1382
+ zodType = z.uuid();
1231
1383
  } else if (isVirtualProp(prop)) {
1232
1384
  zodType = await this.getZodTypeById(prop.id);
1233
1385
  } else if (isRelationProp(prop)) {
@@ -1255,7 +1407,9 @@ export class Syncer {
1255
1407
  key: string,
1256
1408
  zodType: z.ZodTypeAny
1257
1409
  ): RenderingNode["renderType"] {
1258
- if (zodType instanceof z.ZodString) {
1410
+ if (zodType instanceof z.ZodDate) {
1411
+ return "datetime";
1412
+ } else if (zodType instanceof z.ZodString) {
1259
1413
  if (key.includes("img") || key.includes("image")) {
1260
1414
  return "string-image";
1261
1415
  } else if (zodType.description === "SQLDateTimeString") {
@@ -1286,11 +1440,12 @@ export class Syncer {
1286
1440
  } else if (zodType instanceof z.ZodLiteral) {
1287
1441
  return "string-plain";
1288
1442
  } else {
1289
- throw new Error(`타입 파싱 불가 ${key} ${zodType._def.typeName}`);
1443
+ throw new Error(`타입 파싱 불가 ${key} ${zodType.def.type}`);
1290
1444
  }
1291
1445
  }
1446
+
1292
1447
  zodTypeToRenderingNode(
1293
- zodType: z.ZodTypeAny,
1448
+ zodType: z.ZodType<any>,
1294
1449
  baseKey: string = "root"
1295
1450
  ): RenderingNode {
1296
1451
  const def = {
@@ -1310,7 +1465,7 @@ export class Syncer {
1310
1465
  children,
1311
1466
  };
1312
1467
  } else if (zodType instanceof z.ZodArray) {
1313
- const innerType = zodType._def.type;
1468
+ const innerType = (zodType as z.ZodArray<z.ZodType<any>>).def.element;
1314
1469
  if (innerType instanceof z.ZodString && baseKey.includes("images")) {
1315
1470
  return {
1316
1471
  ...def,
@@ -1323,19 +1478,19 @@ export class Syncer {
1323
1478
  element: this.zodTypeToRenderingNode(innerType, baseKey),
1324
1479
  };
1325
1480
  } else if (zodType instanceof z.ZodUnion) {
1326
- const optionNodes = zodType._def.options.map((opt: z.ZodTypeAny) =>
1481
+ const optionNodes = (zodType as z.ZodUnion<z.ZodType[]>).def.options.map((opt) =>
1327
1482
  this.zodTypeToRenderingNode(opt, baseKey)
1328
1483
  );
1329
1484
  // TODO: ZodUnion이 들어있는 경우 핸들링
1330
1485
  return optionNodes[0];
1331
1486
  } else if (zodType instanceof z.ZodOptional) {
1332
1487
  return {
1333
- ...this.zodTypeToRenderingNode(zodType._def.innerType, baseKey),
1488
+ ...this.zodTypeToRenderingNode((zodType as z.ZodOptional<z.ZodType>).def.innerType, baseKey),
1334
1489
  optional: true,
1335
1490
  };
1336
1491
  } else if (zodType instanceof z.ZodNullable) {
1337
1492
  return {
1338
- ...this.zodTypeToRenderingNode(zodType._def.innerType, baseKey),
1493
+ ...this.zodTypeToRenderingNode((zodType as z.ZodNullable<z.ZodType>).def.innerType, baseKey),
1339
1494
  nullable: true,
1340
1495
  };
1341
1496
  } else {
@@ -1350,7 +1505,7 @@ export class Syncer {
1350
1505
  entityId: string,
1351
1506
  subsetKey: string
1352
1507
  ): Promise<RenderingNode> {
1353
- const entity = await EntityManager.get(entityId);
1508
+ const entity = EntityManager.get(entityId);
1354
1509
  const subsetA = entity.subsets[subsetKey];
1355
1510
  if (subsetA === undefined) {
1356
1511
  throw new ServiceUnavailableException("SubsetA 가 없습니다.");
@@ -1423,17 +1578,19 @@ export class Syncer {
1423
1578
  // reload entities
1424
1579
  await EntityManager.reload();
1425
1580
 
1426
- // generate schemas, types
1427
- await Promise.all([
1428
- this.actionGenerateSchemas(),
1429
- ...(form.parentId === undefined
1430
- ? [
1431
- this.generateTemplate("init_types", {
1432
- entityId: form.entityId,
1433
- }),
1434
- ]
1435
- : []),
1436
- ]);
1581
+ // syncFromWatcher에서 처리하므로 주석처리
1582
+ // this.actionGenerateSchemas();
1583
+
1584
+ // // generate schemas, types
1585
+ // await Promise.all([
1586
+ // ...(form.parentId === undefined
1587
+ // ? [
1588
+ // this.generateTemplate("init_types", {
1589
+ // entityId: form.entityId,
1590
+ // }),
1591
+ // ]
1592
+ // : []),
1593
+ // ]);
1437
1594
  }
1438
1595
 
1439
1596
  async delEntity(entityId: string): Promise<{ delPaths: string[] }> {
@@ -1458,9 +1615,9 @@ export class Syncer {
1458
1615
  })(); // iife
1459
1616
 
1460
1617
  for await (const delPath of delPaths) {
1461
- if (fs.existsSync(delPath)) {
1618
+ if (await exists(delPath)) {
1462
1619
  console.log(chalk.red(`DELETE ${delPath}`));
1463
- execSync(`rm -rf ${delPath}`);
1620
+ await rm(delPath, { recursive: true, force: true });
1464
1621
  } else {
1465
1622
  console.log(chalk.yellow(`NOT_EXISTS ${delPath}`));
1466
1623
  }
@@ -1471,4 +1628,14 @@ export class Syncer {
1471
1628
 
1472
1629
  return { delPaths };
1473
1630
  }
1631
+
1632
+ syncUI() {
1633
+ const uiPort = Sonamu.config.ui?.port ?? 57000;
1634
+
1635
+ fetch(`http://127.0.0.1:${uiPort}/api/reload`, {
1636
+ method: "GET",
1637
+ }).catch((e) =>
1638
+ console.log(chalk.dim(`Failed to reload Sonamu UI: ${e.message}`))
1639
+ );
1640
+ }
1474
1641
  }