sonamu 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.swcrc.project-default +18 -0
- package/bin/cli.js +24 -0
- package/dist/ai/agents/agent.d.ts +11 -0
- package/dist/ai/agents/agent.d.ts.map +1 -0
- package/dist/ai/agents/agent.js +65 -0
- package/dist/ai/agents/index.d.ts +3 -0
- package/dist/ai/agents/index.d.ts.map +1 -0
- package/dist/ai/agents/index.js +4 -0
- package/dist/ai/agents/types.d.ts +43 -0
- package/dist/ai/agents/types.d.ts.map +1 -0
- package/dist/ai/agents/types.js +3 -0
- package/dist/ai/index.d.ts +2 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +3 -0
- package/dist/ai/providers/rtzr/api.d.ts +22 -0
- package/dist/ai/providers/rtzr/api.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/api.js +28 -0
- package/dist/ai/providers/rtzr/error.d.ts +18 -0
- package/dist/ai/providers/rtzr/error.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/error.js +29 -0
- package/dist/ai/providers/rtzr/index.d.ts +5 -0
- package/dist/ai/providers/rtzr/index.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/index.js +6 -0
- package/dist/ai/providers/rtzr/model.d.ts +52 -0
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/model.js +137 -0
- package/dist/ai/providers/rtzr/options.d.ts +7 -0
- package/dist/ai/providers/rtzr/options.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/options.js +47 -0
- package/dist/ai/providers/rtzr/provider.d.ts +18 -0
- package/dist/ai/providers/rtzr/provider.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/provider.js +54 -0
- package/dist/ai/providers/rtzr/utils.d.ts +19 -0
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/utils.js +88 -0
- package/dist/api/base-frame.d.ts +2 -2
- package/dist/api/base-frame.d.ts.map +1 -1
- package/dist/api/base-frame.js +2 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +6 -1
- package/dist/api/code-converters.d.ts +58 -14
- package/dist/api/code-converters.d.ts.map +1 -1
- package/dist/api/code-converters.js +178 -409
- package/dist/api/config.d.ts +27 -13
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +19 -26
- package/dist/api/context.d.ts +4 -3
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +1 -1
- package/dist/api/decorators.d.ts +20 -6
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +111 -18
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +3 -3
- package/dist/api/sonamu.d.ts +7 -7
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +83 -51
- package/dist/api/validator.d.ts +6 -0
- package/dist/api/validator.d.ts.map +1 -0
- package/dist/api/validator.js +81 -0
- package/dist/bin/build-config.d.ts +5 -1
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +5 -2
- package/dist/bin/cli.js +165 -64
- package/dist/bin/loader-register.d.ts +2 -0
- package/dist/bin/loader-register.d.ts.map +1 -0
- package/dist/bin/loader-register.js +34 -0
- package/dist/database/_batch_update.d.ts +5 -3
- package/dist/database/_batch_update.d.ts.map +1 -1
- package/dist/database/_batch_update.js +30 -13
- package/dist/database/base-model.d.ts +96 -10
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +232 -89
- package/dist/database/base-model.types.d.ts +93 -0
- package/dist/database/base-model.types.d.ts.map +1 -0
- package/dist/database/base-model.types.js +10 -0
- package/dist/database/code-generator.d.ts +1 -1
- package/dist/database/code-generator.d.ts.map +1 -1
- package/dist/database/code-generator.js +11 -10
- package/dist/database/db.d.ts +5 -6
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +22 -25
- package/dist/database/puri-subset.test-d.js +81 -0
- package/dist/database/puri-subset.types.d.ts +123 -0
- package/dist/database/puri-subset.types.d.ts.map +1 -0
- package/dist/database/puri-subset.types.js +16 -0
- package/dist/database/puri-wrapper.d.ts +13 -11
- package/dist/database/puri-wrapper.d.ts.map +1 -1
- package/dist/database/puri-wrapper.js +2 -2
- package/dist/database/puri.d.ts +25 -14
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +83 -21
- package/dist/database/puri.types.d.ts +21 -7
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +4 -1
- package/dist/database/transaction-context.d.ts +1 -1
- package/dist/database/transaction-context.d.ts.map +1 -1
- package/dist/database/transaction-context.js +1 -1
- package/dist/database/upsert-builder.d.ts +9 -3
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +227 -78
- package/dist/entity/entity-manager.d.ts +165 -2
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +26 -10
- package/dist/entity/entity.d.ts +5 -3
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +153 -54
- package/dist/exceptions/error-handler.d.ts +1 -1
- package/dist/exceptions/error-handler.d.ts.map +1 -1
- package/dist/exceptions/error-handler.js +1 -1
- package/dist/exceptions/so-exceptions.d.ts +1 -1
- package/dist/exceptions/so-exceptions.d.ts.map +1 -1
- package/dist/exceptions/so-exceptions.js +1 -1
- package/dist/file-storage/driver.d.ts +1 -1
- package/dist/file-storage/driver.d.ts.map +1 -1
- package/dist/file-storage/driver.js +1 -1
- package/dist/file-storage/file-storage.js +2 -2
- package/dist/index.d.ts +18 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -13
- package/dist/migration/code-generation.d.ts +1 -1
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +123 -67
- package/dist/migration/migration-set.d.ts +2 -10
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +67 -218
- package/dist/migration/migrator.d.ts +24 -73
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +121 -301
- package/dist/migration/postgresql-schema-reader.d.ts +51 -0
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -0
- package/dist/migration/postgresql-schema-reader.js +245 -0
- package/dist/migration/types.d.ts +6 -38
- package/dist/migration/types.d.ts.map +1 -1
- package/dist/migration/types.js +1 -1
- package/dist/naite/messaging-types.d.ts +43 -0
- package/dist/naite/messaging-types.d.ts.map +1 -0
- package/dist/naite/messaging-types.js +7 -0
- package/dist/naite/naite-reporter.d.ts +41 -0
- package/dist/naite/naite-reporter.d.ts.map +1 -0
- package/dist/naite/naite-reporter.js +102 -0
- package/dist/naite/naite.d.ts +91 -8
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/naite/naite.js +285 -41
- package/dist/stream/sse.d.ts +2 -2
- package/dist/stream/sse.d.ts.map +1 -1
- package/dist/stream/sse.js +1 -1
- package/dist/syncer/api-parser.d.ts +3 -13
- package/dist/syncer/api-parser.d.ts.map +1 -1
- package/dist/syncer/api-parser.js +67 -56
- package/dist/syncer/checksum.d.ts +2 -2
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +11 -11
- package/dist/syncer/code-generator.d.ts +3 -3
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +37 -17
- package/dist/syncer/entity-operations.d.ts +2 -2
- package/dist/syncer/entity-operations.d.ts.map +1 -1
- package/dist/syncer/entity-operations.js +9 -8
- package/dist/syncer/file-patterns.d.ts +1 -1
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +1 -1
- package/dist/syncer/index.d.ts +4 -4
- package/dist/syncer/index.d.ts.map +1 -1
- package/dist/syncer/index.js +5 -5
- package/dist/syncer/module-loader.d.ts +4 -4
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +17 -12
- package/dist/syncer/syncer.d.ts +31 -24
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +92 -45
- package/dist/template/entity-converter.d.ts +1 -1
- package/dist/template/entity-converter.d.ts.map +1 -1
- package/dist/template/entity-converter.js +15 -8
- package/dist/template/helpers.d.ts +2 -2
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +3 -3
- package/dist/template/implementations/entity.template.d.ts +2 -2
- package/dist/template/implementations/entity.template.d.ts.map +1 -1
- package/dist/template/implementations/entity.template.js +4 -5
- package/dist/template/implementations/generated.template.d.ts +2 -3
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +46 -29
- package/dist/template/implementations/generated_http.template.d.ts +2 -3
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +9 -9
- package/dist/template/implementations/generated_sso.template.d.ts +3 -4
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +54 -25
- package/dist/template/implementations/init_types.template.d.ts +2 -2
- package/dist/template/implementations/init_types.template.d.ts.map +1 -1
- package/dist/template/implementations/init_types.template.js +2 -2
- package/dist/template/implementations/model.template.d.ts +2 -2
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.js +47 -37
- package/dist/template/implementations/model_test.template.d.ts +2 -2
- package/dist/template/implementations/model_test.template.d.ts.map +1 -1
- package/dist/template/implementations/model_test.template.js +2 -2
- package/dist/template/implementations/service.template.d.ts +4 -4
- package/dist/template/implementations/service.template.d.ts.map +1 -1
- package/dist/template/implementations/service.template.js +24 -16
- package/dist/template/implementations/view_enums_buttonset.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_buttonset.template.js +1 -1
- package/dist/template/implementations/view_enums_dropdown.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_dropdown.template.js +2 -2
- package/dist/template/implementations/view_enums_select.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_select.template.js +2 -2
- package/dist/template/implementations/view_form.template.d.ts +2 -2
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +4 -4
- package/dist/template/implementations/view_id_all_select.template.d.ts +2 -2
- package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_all_select.template.js +1 -1
- package/dist/template/implementations/view_id_async_select.template.d.ts +2 -2
- package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_async_select.template.js +1 -1
- package/dist/template/implementations/view_list.template.d.ts +2 -2
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +29 -19
- package/dist/template/implementations/view_list_columns.template.d.ts +3 -3
- package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list_columns.template.js +1 -1
- package/dist/template/implementations/view_search_input.template.d.ts +2 -2
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
- package/dist/template/implementations/view_search_input.template.js +1 -1
- package/dist/template/index.d.ts +4 -2
- package/dist/template/index.d.ts.map +1 -1
- package/dist/template/index.js +5 -3
- package/dist/template/template-manager.d.ts +56 -0
- package/dist/template/template-manager.d.ts.map +1 -0
- package/dist/template/template-manager.js +125 -0
- package/dist/template/template-types.d.ts +16 -0
- package/dist/template/template-types.d.ts.map +1 -0
- package/dist/template/template-types.js +7 -0
- package/dist/template/template.d.ts +12 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +19 -6
- package/dist/template/zod-converter.d.ts +40 -7
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +386 -58
- package/dist/testing/_relation-graph.d.ts +1 -1
- package/dist/testing/_relation-graph.d.ts.map +1 -1
- package/dist/testing/_relation-graph.js +12 -3
- package/dist/testing/fixture-manager.d.ts +42 -11
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +338 -236
- package/dist/types/types.d.ts +709 -104
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +309 -52
- package/dist/typings/knex.d.js +2 -2
- package/dist/utils/async-utils.d.ts.map +1 -1
- package/dist/utils/async-utils.js +3 -3
- package/dist/utils/console-util.js +1 -1
- package/dist/utils/controller.d.ts +1 -0
- package/dist/utils/controller.d.ts.map +1 -1
- package/dist/utils/controller.js +4 -1
- package/dist/utils/esm-utils.d.ts +0 -6
- package/dist/utils/esm-utils.d.ts.map +1 -1
- package/dist/utils/esm-utils.js +2 -9
- package/dist/utils/formatter.d.ts +3 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +110 -0
- package/dist/utils/fs-utils.d.ts +1 -1
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +1 -1
- package/dist/utils/lodash-able.d.ts.map +1 -1
- package/dist/utils/lodash-able.js +1 -1
- package/dist/utils/object-utils.d.ts +44 -0
- package/dist/utils/object-utils.d.ts.map +1 -0
- package/dist/utils/object-utils.js +191 -0
- package/dist/utils/path-utils.d.ts +1 -1
- package/dist/utils/path-utils.d.ts.map +1 -1
- package/dist/utils/path-utils.js +3 -3
- package/dist/utils/process-utils.js +1 -1
- package/dist/utils/sql-parser.d.ts +5 -1
- package/dist/utils/sql-parser.d.ts.map +1 -1
- package/dist/utils/sql-parser.js +14 -3
- package/dist/utils/type-utils.d.ts +23 -0
- package/dist/utils/type-utils.d.ts.map +1 -0
- package/dist/utils/type-utils.js +45 -0
- package/dist/utils/utils.d.ts +7 -1
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +44 -5
- package/dist/utils/zod-error.d.ts +1 -1
- package/dist/utils/zod-error.d.ts.map +1 -1
- package/dist/utils/zod-error.js +1 -1
- package/package.json +55 -30
- package/src/ai/agents/agent.ts +87 -0
- package/src/ai/agents/index.ts +2 -0
- package/src/ai/agents/types.ts +47 -0
- package/src/ai/index.ts +1 -0
- package/src/ai/providers/rtzr/api.ts +37 -0
- package/src/ai/providers/rtzr/error.ts +34 -0
- package/src/ai/providers/rtzr/index.ts +4 -0
- package/src/ai/providers/rtzr/model.ts +201 -0
- package/src/ai/providers/rtzr/options.ts +49 -0
- package/src/ai/providers/rtzr/provider.ts +91 -0
- package/src/ai/providers/rtzr/utils.ts +127 -0
- package/src/api/base-frame.ts +4 -2
- package/src/api/caster.ts +17 -23
- package/src/api/code-converters.ts +176 -533
- package/src/api/config.ts +39 -56
- package/src/api/context.ts +7 -18
- package/src/api/decorators.ts +175 -46
- package/src/api/index.ts +2 -2
- package/src/api/sonamu.ts +133 -124
- package/src/api/validator.ts +83 -0
- package/src/bin/build-config.ts +7 -1
- package/src/bin/cli.ts +192 -110
- package/src/bin/loader-register.ts +38 -0
- package/src/database/_batch_update.ts +46 -31
- package/src/database/base-model.ts +390 -182
- package/src/database/base-model.types.ts +155 -0
- package/src/database/code-generator.ts +13 -32
- package/src/database/db.ts +36 -50
- package/src/database/puri-subset.test-d.ts +471 -0
- package/src/database/puri-subset.types.ts +195 -0
- package/src/database/puri-wrapper.ts +58 -67
- package/src/database/puri.ts +182 -126
- package/src/database/puri.types.ts +64 -31
- package/src/database/transaction-context.ts +1 -1
- package/src/database/upsert-builder.ts +261 -132
- package/src/entity/entity-manager.ts +36 -28
- package/src/entity/entity.ts +330 -249
- package/src/exceptions/error-handler.ts +3 -3
- package/src/exceptions/so-exceptions.ts +11 -11
- package/src/file-storage/driver.ts +5 -5
- package/src/file-storage/file-storage.ts +2 -2
- package/src/index.ts +18 -12
- package/src/migration/code-generation.ts +185 -172
- package/src/migration/migration-set.ts +80 -293
- package/src/migration/migrator.ts +182 -425
- package/src/migration/mysql-schema-reader.ts.txt +272 -0
- package/src/migration/postgresql-schema-reader.ts +310 -0
- package/src/migration/types.ts +6 -39
- package/src/naite/messaging-types.ts +51 -0
- package/src/naite/naite-reporter.ts +128 -0
- package/src/naite/naite.ts +378 -33
- package/src/shared/web.shared.ts.txt +20 -24
- package/src/stream/sse.ts +5 -5
- package/src/syncer/api-parser.ts +52 -69
- package/src/syncer/checksum.ts +25 -37
- package/src/syncer/code-generator.ts +58 -62
- package/src/syncer/entity-operations.ts +12 -15
- package/src/syncer/file-patterns.ts +2 -2
- package/src/syncer/index.ts +4 -4
- package/src/syncer/module-loader.ts +28 -25
- package/src/syncer/syncer.ts +155 -162
- package/src/template/entity-converter.ts +18 -27
- package/src/template/helpers.ts +8 -11
- package/src/template/implementations/entity.template.ts +6 -6
- package/src/template/implementations/generated.template.ts +99 -99
- package/src/template/implementations/generated_http.template.ts +21 -54
- package/src/template/implementations/generated_sso.template.ts +78 -65
- package/src/template/implementations/init_types.template.ts +4 -6
- package/src/template/implementations/model.template.ts +47 -38
- package/src/template/implementations/model_test.template.ts +3 -3
- package/src/template/implementations/service.template.ts +56 -80
- package/src/template/implementations/view_enums_buttonset.template.ts +2 -2
- package/src/template/implementations/view_enums_dropdown.template.ts +4 -4
- package/src/template/implementations/view_enums_select.template.ts +3 -3
- package/src/template/implementations/view_form.template.ts +34 -75
- package/src/template/implementations/view_id_all_select.template.ts +2 -2
- package/src/template/implementations/view_id_async_select.template.ts +9 -23
- package/src/template/implementations/view_list.template.ts +54 -95
- package/src/template/implementations/view_list_columns.template.ts +4 -10
- package/src/template/implementations/view_search_input.template.ts +2 -2
- package/src/template/index.ts +4 -2
- package/src/template/template-manager.ts +166 -0
- package/src/template/template-types.ts +16 -0
- package/src/template/template.ts +29 -10
- package/src/template/zod-converter.ts +459 -101
- package/src/testing/_relation-graph.ts +18 -11
- package/src/testing/fixture-manager.ts +468 -362
- package/src/types/types.ts +516 -248
- package/src/typings/knex.d.ts +7 -9
- package/src/utils/async-utils.ts +8 -12
- package/src/utils/console-util.ts +1 -1
- package/src/utils/controller.ts +3 -0
- package/src/utils/esm-utils.ts +8 -18
- package/src/utils/formatter.ts +109 -0
- package/src/utils/fs-utils.ts +1 -1
- package/src/utils/lodash-able.ts +1 -4
- package/src/utils/object-utils.ts +217 -0
- package/src/utils/path-utils.ts +3 -6
- package/src/utils/process-utils.ts +1 -1
- package/src/utils/sql-parser.ts +23 -5
- package/src/utils/type-utils.ts +83 -0
- package/src/utils/utils.ts +58 -9
- package/src/utils/zod-error.ts +3 -3
- package/dist/bin/cli-wrapper.d.ts +0 -3
- package/dist/bin/cli-wrapper.d.ts.map +0 -1
- package/dist/bin/cli-wrapper.js +0 -72
- package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +0 -2
- package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +0 -1
- package/dist/database/knex-plugins/knex-on-duplicate-update.js +0 -39
- package/dist/entity/entity-utils.d.ts +0 -61
- package/dist/entity/entity-utils.d.ts.map +0 -1
- package/dist/entity/entity-utils.js +0 -210
- package/src/bin/cli-wrapper.ts +0 -82
- package/src/database/knex-plugins/knex-on-duplicate-update.ts +0 -45
- package/src/entity/entity-utils.ts +0 -291
package/src/template/template.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { EntityNamesRecord } from "../entity/entity-manager";
|
|
1
|
+
import path from "path";
|
|
2
|
+
import type { EntityNamesRecord } from "../entity/entity-manager";
|
|
3
|
+
import type { TemplateKey, TemplateOptions } from "../types/types";
|
|
3
4
|
import { globAsync } from "../utils/async-utils";
|
|
4
5
|
import { importMembers } from "../utils/esm-utils";
|
|
5
|
-
import path from "path";
|
|
6
6
|
|
|
7
7
|
export type RenderedTemplate = {
|
|
8
8
|
target: string;
|
|
@@ -27,15 +27,17 @@ export abstract class Template {
|
|
|
27
27
|
/**
|
|
28
28
|
* 템플릿 구현체가 있는 디렉토리의 모든 템플릿을 로드합니다.
|
|
29
29
|
* 템플릿이 필요(Template.find)해지기 전에 최소 한 번 호출해주셔야 합니다.
|
|
30
|
+
* @deprecated TemplateManager.autoload() 사용 권장
|
|
30
31
|
*/
|
|
31
32
|
public static async autoload() {
|
|
32
33
|
const templateFiles = await globAsync(
|
|
33
34
|
// Sonamu의 코드베이스는 항상 빌드된 채로 dist 속에 머무르므로,
|
|
34
35
|
// 현재 파일을 기준으로 마찬가지로 dist 속에 있는 템플릿 구현체 js 파일들을 찾습니다.
|
|
35
|
-
path.join(import.meta.dirname, "implementations/*.template.js")
|
|
36
|
+
path.join(import.meta.dirname, "implementations/*.template.js"),
|
|
36
37
|
);
|
|
37
38
|
|
|
38
39
|
for (const templateFile of templateFiles) {
|
|
40
|
+
// biome-ignore lint/suspicious/noExplicitAny: importMembers의 반환 타입을 명시적으로 지정할 수 없음
|
|
39
41
|
const templates = await importMembers<any>(templateFile);
|
|
40
42
|
if (
|
|
41
43
|
templates.length === 1 &&
|
|
@@ -44,10 +46,10 @@ export abstract class Template {
|
|
|
44
46
|
) {
|
|
45
47
|
// 클래스의 인스턴스를 생성하여 등록
|
|
46
48
|
const instance = new templates[0].value();
|
|
47
|
-
|
|
49
|
+
Template.templates.set(instance.key, instance);
|
|
48
50
|
} else {
|
|
49
51
|
throw new Error(
|
|
50
|
-
`Template ${templateFile} should export only one class that extends Template
|
|
52
|
+
`Template ${templateFile} should export only one class that extends Template`,
|
|
51
53
|
);
|
|
52
54
|
}
|
|
53
55
|
}
|
|
@@ -60,17 +62,34 @@ export abstract class Template {
|
|
|
60
62
|
/**
|
|
61
63
|
* 템플릿 **인스턴스**를 key로 찾아옵니다.
|
|
62
64
|
* 만약 템플릿이 로드(loadAll)되지 않았거나 찾는 템플릿이 없다면 에러를 던집니다.
|
|
63
|
-
* @
|
|
64
|
-
* @
|
|
65
|
+
* @deprecated TemplateManager.get() 사용 권장
|
|
66
|
+
* @param key
|
|
67
|
+
* @returns
|
|
65
68
|
*/
|
|
66
69
|
public static find(key: TemplateKey): Template {
|
|
67
|
-
const instance =
|
|
70
|
+
const instance = Template.templates.get(key);
|
|
68
71
|
if (!instance) {
|
|
69
|
-
throw new Error(
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Template ${key} not found. It might be becasuse you tried to find a template before loading all templates. Did you call Template.loadAll()?`,
|
|
74
|
+
);
|
|
70
75
|
}
|
|
71
76
|
return instance;
|
|
72
77
|
}
|
|
73
78
|
|
|
79
|
+
/**
|
|
80
|
+
* 내부용: TemplateManager에서 사용
|
|
81
|
+
*/
|
|
82
|
+
public static _getTemplatesMap(): Map<TemplateKey, Template> {
|
|
83
|
+
return Template.templates;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 내부용: TemplateManager에서 사용
|
|
88
|
+
*/
|
|
89
|
+
public static _clearTemplates(): void {
|
|
90
|
+
Template.templates.clear();
|
|
91
|
+
}
|
|
92
|
+
|
|
74
93
|
public abstract render(
|
|
75
94
|
options: TemplateOptions[TemplateKey],
|
|
76
95
|
...extra: unknown[]
|
|
@@ -1,46 +1,75 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* zod-converter 구성
|
|
3
|
+
* 1. 유틸리티
|
|
4
|
+
* - getZodTypeById
|
|
5
|
+
*
|
|
6
|
+
* 2. Zod 타입 변환 (EntityProp -> ZodType)
|
|
7
|
+
* - propToZodType
|
|
8
|
+
*
|
|
9
|
+
* 3. EntityProp/Node -> Zod 코드 문자열
|
|
10
|
+
* - propToZodTypeDef
|
|
11
|
+
* - propNodeToZodTypeDef
|
|
12
|
+
*
|
|
13
|
+
* 4. Zod 타입 인스턴스를 해당하는 Zod 코드 문자열로 변환 (ZodType -> ZodCode)
|
|
14
|
+
* - zodTypeToZodCode
|
|
15
|
+
*
|
|
16
|
+
* 5. Zod 타입을 UI 렌더링에 사용할 수 있는 RenderingNode로 변환 (ZodType -> RenderingNode)
|
|
17
|
+
* - zodTypeToRenderingNode
|
|
18
|
+
* - resolveRenderType
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import inflection from "inflection";
|
|
22
|
+
import path from "path";
|
|
23
|
+
import { z } from "zod";
|
|
24
|
+
import type { $ZodLooseShape } from "zod/v4/core";
|
|
25
|
+
import { Sonamu } from "../api/sonamu";
|
|
2
26
|
import { EntityManager } from "../entity/entity-manager";
|
|
3
27
|
import {
|
|
4
|
-
EntityProp,
|
|
28
|
+
type EntityProp,
|
|
29
|
+
type EntityPropNode,
|
|
5
30
|
isBelongsToOneRelationProp,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
31
|
+
isBigIntegerArrayProp,
|
|
32
|
+
isBigIntegerSingleProp,
|
|
33
|
+
isBooleanArrayProp,
|
|
34
|
+
isBooleanSingleProp,
|
|
35
|
+
isDateArrayProp,
|
|
36
|
+
isDateSingleProp,
|
|
37
|
+
isEnumArrayProp,
|
|
38
|
+
isEnumSingleProp,
|
|
39
|
+
isIntegerArrayProp,
|
|
40
|
+
isIntegerSingleProp,
|
|
15
41
|
isJsonProp,
|
|
42
|
+
isNumberArrayProp,
|
|
43
|
+
isNumberSingleProp,
|
|
44
|
+
isNumericArrayProp,
|
|
45
|
+
isNumericSingleProp,
|
|
16
46
|
isOneToOneRelationProp,
|
|
17
47
|
isRelationProp,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
isUuidProp,
|
|
48
|
+
isStringArrayProp,
|
|
49
|
+
isStringSingleProp,
|
|
50
|
+
isUuidArrayProp,
|
|
51
|
+
isUuidSingleProp,
|
|
23
52
|
isVirtualProp,
|
|
24
|
-
RenderingNode,
|
|
53
|
+
type RenderingNode,
|
|
25
54
|
} from "../types/types";
|
|
26
|
-
import path from "path";
|
|
27
55
|
import { createImportUrl } from "../utils/esm-utils";
|
|
28
|
-
import { Sonamu } from "../api/sonamu";
|
|
29
|
-
import inflection from "inflection";
|
|
30
|
-
import { getTextTypeLength } from "../api";
|
|
31
56
|
|
|
57
|
+
// <any>를 자제하고, Zod에서 제약하는 기본적인 Generic Type Parameter를 사용함.
|
|
58
|
+
type AnyZodRecord = z.ZodRecord<z.ZodString | z.ZodNumber | z.ZodSymbol, z.ZodType>;
|
|
59
|
+
type AnyZodObject = z.ZodObject<$ZodLooseShape>;
|
|
60
|
+
type AnyZodNullable = z.ZodNullable<z.ZodType>;
|
|
61
|
+
type AnyZodDefault = z.ZodDefault<z.ZodType>;
|
|
62
|
+
type AnyZodUnion = z.ZodUnion<z.ZodType[]>;
|
|
63
|
+
type AnyZodArray = z.ZodArray<z.ZodType>;
|
|
64
|
+
type AnyZodOptional = z.ZodOptional<z.ZodType>;
|
|
65
|
+
type AnyZodTemplateLiteral = z.ZodTemplateLiteral<string>;
|
|
32
66
|
/**
|
|
33
67
|
* Zod 타입 ID로부터 동적으로 Zod 스키마를 로드합니다.
|
|
34
68
|
* dist 디렉토리에서 ESM으로 import하여 가져옵니다.
|
|
35
69
|
*/
|
|
36
70
|
export async function getZodTypeById(zodTypeId: string): Promise<z.ZodTypeAny> {
|
|
37
71
|
const modulePath = EntityManager.getModulePath(zodTypeId);
|
|
38
|
-
const moduleAbsPath = path.join(
|
|
39
|
-
Sonamu.apiRootPath,
|
|
40
|
-
"dist",
|
|
41
|
-
"application",
|
|
42
|
-
modulePath + ".js"
|
|
43
|
-
);
|
|
72
|
+
const moduleAbsPath = path.join(Sonamu.apiRootPath, "dist", "application", `${modulePath}.js`);
|
|
44
73
|
const importUrl = createImportUrl(moduleAbsPath);
|
|
45
74
|
const imported = await import(importUrl);
|
|
46
75
|
|
|
@@ -50,13 +79,408 @@ export async function getZodTypeById(zodTypeId: string): Promise<z.ZodTypeAny> {
|
|
|
50
79
|
return imported[zodTypeId].describe(zodTypeId);
|
|
51
80
|
}
|
|
52
81
|
|
|
82
|
+
/**
|
|
83
|
+
* EntityProp을 Zod 타입으로 변환합니다.
|
|
84
|
+
* 각 prop의 타입에 따라 적절한 Zod validator를 생성합니다.
|
|
85
|
+
*/
|
|
86
|
+
export async function propToZodType(prop: EntityProp): Promise<z.ZodTypeAny> {
|
|
87
|
+
let zodType: z.ZodTypeAny = z.unknown();
|
|
88
|
+
if (isIntegerSingleProp(prop)) {
|
|
89
|
+
zodType = z.number().int();
|
|
90
|
+
} else if (isIntegerArrayProp(prop)) {
|
|
91
|
+
zodType = z.number().int().array();
|
|
92
|
+
} else if (isBigIntegerSingleProp(prop)) {
|
|
93
|
+
zodType = z.bigint();
|
|
94
|
+
} else if (isBigIntegerArrayProp(prop)) {
|
|
95
|
+
zodType = z.bigint().array();
|
|
96
|
+
} else if (isEnumSingleProp(prop)) {
|
|
97
|
+
zodType = await getZodTypeById(prop.id);
|
|
98
|
+
} else if (isEnumArrayProp(prop)) {
|
|
99
|
+
zodType = (await getZodTypeById(prop.id)).array();
|
|
100
|
+
} else if (isStringSingleProp(prop)) {
|
|
101
|
+
if (prop.length) {
|
|
102
|
+
zodType = z.string().max(prop.length);
|
|
103
|
+
} else {
|
|
104
|
+
zodType = z.string();
|
|
105
|
+
}
|
|
106
|
+
} else if (isStringArrayProp(prop)) {
|
|
107
|
+
if (prop.length) {
|
|
108
|
+
zodType = z.string().max(prop.length).array();
|
|
109
|
+
} else {
|
|
110
|
+
zodType = z.string().array();
|
|
111
|
+
}
|
|
112
|
+
} else if (isNumberSingleProp(prop)) {
|
|
113
|
+
zodType = z.number();
|
|
114
|
+
} else if (isNumberArrayProp(prop)) {
|
|
115
|
+
zodType = z.number().array();
|
|
116
|
+
} else if (isNumericSingleProp(prop)) {
|
|
117
|
+
zodType = z.string();
|
|
118
|
+
} else if (isNumericArrayProp(prop)) {
|
|
119
|
+
zodType = z.string().array();
|
|
120
|
+
} else if (isBooleanSingleProp(prop)) {
|
|
121
|
+
zodType = z.boolean();
|
|
122
|
+
} else if (isBooleanArrayProp(prop)) {
|
|
123
|
+
zodType = z.boolean().array();
|
|
124
|
+
} else if (isDateSingleProp(prop)) {
|
|
125
|
+
zodType = z.date();
|
|
126
|
+
} else if (isDateArrayProp(prop)) {
|
|
127
|
+
zodType = z.date().array();
|
|
128
|
+
} else if (isUuidSingleProp(prop)) {
|
|
129
|
+
zodType = z.uuid();
|
|
130
|
+
} else if (isUuidArrayProp(prop)) {
|
|
131
|
+
zodType = z.uuid().array();
|
|
132
|
+
} else if (isJsonProp(prop)) {
|
|
133
|
+
zodType = await getZodTypeById(prop.id);
|
|
134
|
+
} else if (isVirtualProp(prop)) {
|
|
135
|
+
zodType = await getZodTypeById(prop.id);
|
|
136
|
+
} else if (isRelationProp(prop)) {
|
|
137
|
+
if (isBelongsToOneRelationProp(prop) || (isOneToOneRelationProp(prop) && prop.hasJoinColumn)) {
|
|
138
|
+
zodType = z.number().int();
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
throw new Error(`prop을 zodType으로 변환하는데 실패 ${prop}}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if ((prop as { unsigned?: boolean }).unsigned) {
|
|
145
|
+
zodType = (zodType as z.ZodNumber).nonnegative();
|
|
146
|
+
}
|
|
147
|
+
if (prop.nullable) {
|
|
148
|
+
zodType = zodType.nullable();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return zodType;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* EntityProp을 Zod 타입 정의 코드 문자열로 변환합니다.
|
|
156
|
+
*/
|
|
157
|
+
export function propToZodTypeDef(prop: EntityProp, injectImportKeys: string[]): string {
|
|
158
|
+
let stmt: string;
|
|
159
|
+
if (isIntegerSingleProp(prop)) {
|
|
160
|
+
stmt = `${prop.name}: z.int()`;
|
|
161
|
+
} else if (isIntegerArrayProp(prop)) {
|
|
162
|
+
stmt = `${prop.name}: z.int().array()`;
|
|
163
|
+
} else if (isBigIntegerSingleProp(prop)) {
|
|
164
|
+
stmt = `${prop.name}: z.bigint()`;
|
|
165
|
+
} else if (isBigIntegerArrayProp(prop)) {
|
|
166
|
+
stmt = `${prop.name}: z.bigint().array()`;
|
|
167
|
+
} else if (isEnumSingleProp(prop)) {
|
|
168
|
+
stmt = `${prop.name}: ${prop.id}`;
|
|
169
|
+
injectImportKeys.push(prop.id);
|
|
170
|
+
} else if (isEnumArrayProp(prop)) {
|
|
171
|
+
stmt = `${prop.name}: ${prop.id}.array()`;
|
|
172
|
+
injectImportKeys.push(prop.id);
|
|
173
|
+
} else if (isStringSingleProp(prop)) {
|
|
174
|
+
if (prop.length) {
|
|
175
|
+
stmt = `${prop.name}: z.string().max(${prop.length})`;
|
|
176
|
+
} else {
|
|
177
|
+
stmt = `${prop.name}: z.string()`;
|
|
178
|
+
}
|
|
179
|
+
} else if (isStringArrayProp(prop)) {
|
|
180
|
+
if (prop.length) {
|
|
181
|
+
stmt = `${prop.name}: z.string().max(${prop.length}).array()`;
|
|
182
|
+
} else {
|
|
183
|
+
stmt = `${prop.name}: z.string().array()`;
|
|
184
|
+
}
|
|
185
|
+
} else if (isNumberSingleProp(prop)) {
|
|
186
|
+
stmt = `${prop.name}: z.number()`;
|
|
187
|
+
} else if (isNumberArrayProp(prop)) {
|
|
188
|
+
stmt = `${prop.name}: z.number().array()`;
|
|
189
|
+
} else if (isNumericSingleProp(prop)) {
|
|
190
|
+
stmt = `${prop.name}: z.string()`;
|
|
191
|
+
} else if (isNumericArrayProp(prop)) {
|
|
192
|
+
stmt = `${prop.name}: z.string().array()`;
|
|
193
|
+
} else if (isDateSingleProp(prop)) {
|
|
194
|
+
stmt = `${prop.name}: z.date()`;
|
|
195
|
+
} else if (isDateArrayProp(prop)) {
|
|
196
|
+
stmt = `${prop.name}: z.date().array()`;
|
|
197
|
+
} else if (isBooleanSingleProp(prop)) {
|
|
198
|
+
stmt = `${prop.name}: z.boolean()`;
|
|
199
|
+
} else if (isBooleanArrayProp(prop)) {
|
|
200
|
+
stmt = `${prop.name}: z.boolean().array()`;
|
|
201
|
+
} else if (isUuidSingleProp(prop)) {
|
|
202
|
+
stmt = `${prop.name}: z.uuid()`;
|
|
203
|
+
} else if (isUuidArrayProp(prop)) {
|
|
204
|
+
stmt = `${prop.name}: z.uuid().array()`;
|
|
205
|
+
} else if (isJsonProp(prop)) {
|
|
206
|
+
stmt = `${prop.name}: ${prop.id}`;
|
|
207
|
+
injectImportKeys.push(prop.id);
|
|
208
|
+
} else if (isVirtualProp(prop)) {
|
|
209
|
+
stmt = `${prop.name}: ${prop.id}`;
|
|
210
|
+
injectImportKeys.push(prop.id);
|
|
211
|
+
} else if (isRelationProp(prop)) {
|
|
212
|
+
if (isBelongsToOneRelationProp(prop) || (isOneToOneRelationProp(prop) && prop.hasJoinColumn)) {
|
|
213
|
+
stmt = `${prop.name}_id: z.int()`;
|
|
214
|
+
} else {
|
|
215
|
+
// 그외 relation 케이스 제외
|
|
216
|
+
return `// ${prop.name}: ${prop.relationType} ${prop.with}`;
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
return "// unable to resolve";
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if ((prop as { unsigned?: boolean }).unsigned) {
|
|
223
|
+
stmt += ".nonnegative()";
|
|
224
|
+
}
|
|
225
|
+
if (prop.nullable) {
|
|
226
|
+
stmt += ".nullable()";
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return `${stmt},`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* EntityPropNode를 Zod 타입 정의 코드 문자열로 변환합니다.
|
|
234
|
+
* plain, array, object 노드 타입을 재귀적으로 처리하여 중첩 구조를 지원합니다.
|
|
235
|
+
*/
|
|
236
|
+
export function propNodeToZodTypeDef(propNode: EntityPropNode, injectImportKeys: string[]): string {
|
|
237
|
+
if (propNode.nodeType === "plain") {
|
|
238
|
+
return propToZodTypeDef(propNode.prop, injectImportKeys);
|
|
239
|
+
} else if (propNode.nodeType === "array") {
|
|
240
|
+
return [
|
|
241
|
+
propNode.prop ? `${propNode.prop.name}: ` : "",
|
|
242
|
+
"z.array(z.object({",
|
|
243
|
+
propNode.children
|
|
244
|
+
.map((childPropNode) => propNodeToZodTypeDef(childPropNode, injectImportKeys))
|
|
245
|
+
.join("\n"),
|
|
246
|
+
"",
|
|
247
|
+
"})),",
|
|
248
|
+
].join("\n");
|
|
249
|
+
} else if (propNode.nodeType === "object") {
|
|
250
|
+
return [
|
|
251
|
+
propNode.prop ? `${propNode.prop.name}: ` : "",
|
|
252
|
+
"z.object({",
|
|
253
|
+
propNode.children
|
|
254
|
+
.map((childPropNode) => propNodeToZodTypeDef(childPropNode, injectImportKeys))
|
|
255
|
+
.join("\n"),
|
|
256
|
+
"",
|
|
257
|
+
`})${propNode.prop?.nullable ? ".nullable()" : ""},`,
|
|
258
|
+
].join("\n");
|
|
259
|
+
} else {
|
|
260
|
+
throw Error;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function zodTypeToTsTypeDef(zt: z.ZodType): string {
|
|
265
|
+
switch (zt.def.type) {
|
|
266
|
+
case "string":
|
|
267
|
+
case "number":
|
|
268
|
+
case "boolean":
|
|
269
|
+
case "bigint":
|
|
270
|
+
case "date":
|
|
271
|
+
case "null":
|
|
272
|
+
case "undefined":
|
|
273
|
+
case "any":
|
|
274
|
+
case "unknown":
|
|
275
|
+
case "never":
|
|
276
|
+
return zt.def.type;
|
|
277
|
+
case "nullable":
|
|
278
|
+
return `${zodTypeToTsTypeDef((zt as AnyZodNullable).def.innerType)} | null`;
|
|
279
|
+
case "default":
|
|
280
|
+
return zodTypeToTsTypeDef((zt as AnyZodDefault).def.innerType);
|
|
281
|
+
case "record": {
|
|
282
|
+
const recordType = zt as AnyZodRecord;
|
|
283
|
+
return `{ [ key: ${zodTypeToTsTypeDef(recordType.def.keyType)} ]: ${zodTypeToTsTypeDef(recordType.def.valueType)}}`;
|
|
284
|
+
}
|
|
285
|
+
case "literal":
|
|
286
|
+
return Array.from((zt as z.ZodLiteral).values)
|
|
287
|
+
.map((value) => {
|
|
288
|
+
if (typeof value === "string") {
|
|
289
|
+
return `"${value}"`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (value === null) {
|
|
293
|
+
return `null`;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (value === undefined) {
|
|
297
|
+
return `undefined`;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return `${value}`;
|
|
301
|
+
})
|
|
302
|
+
.join(" | ");
|
|
303
|
+
case "union":
|
|
304
|
+
return `${(zt as AnyZodUnion).options
|
|
305
|
+
.map((option) => zodTypeToTsTypeDef(option))
|
|
306
|
+
.join(" | ")}`;
|
|
307
|
+
case "enum":
|
|
308
|
+
return `${(zt as z.ZodEnum).options.map((val) => `"${val}"`).join(" | ")}`;
|
|
309
|
+
case "array":
|
|
310
|
+
return `${zodTypeToTsTypeDef((zt as AnyZodArray).element)}[]`;
|
|
311
|
+
case "object": {
|
|
312
|
+
const shape = (zt as AnyZodObject).shape;
|
|
313
|
+
return [
|
|
314
|
+
"{",
|
|
315
|
+
...Object.keys(shape).map((key) => {
|
|
316
|
+
if (shape[key].def.type === "optional") {
|
|
317
|
+
return `${key}?: ${zodTypeToTsTypeDef(shape[key].def.innerType)},`;
|
|
318
|
+
} else {
|
|
319
|
+
return `${key}: ${zodTypeToTsTypeDef(shape[key])},`;
|
|
320
|
+
}
|
|
321
|
+
}),
|
|
322
|
+
"}",
|
|
323
|
+
].join("\n");
|
|
324
|
+
}
|
|
325
|
+
case "optional":
|
|
326
|
+
return `${zodTypeToTsTypeDef((zt as AnyZodOptional).def.innerType)} | undefined`;
|
|
327
|
+
case "template_literal": {
|
|
328
|
+
const def = (zt as AnyZodTemplateLiteral).def;
|
|
329
|
+
|
|
330
|
+
// 빈 template literal은 string으로 폴백
|
|
331
|
+
if (!def.parts || def.parts.length === 0) {
|
|
332
|
+
return "string";
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// 각 part를 TypeScript 타입 문자열로 변환
|
|
336
|
+
const parts = def.parts.map((part: unknown) => {
|
|
337
|
+
// 리터럴 값 (string, number, boolean, null, undefined)
|
|
338
|
+
if (typeof part === "string") {
|
|
339
|
+
return `${part}`;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ZodType - 재귀적으로 변환
|
|
343
|
+
if (part && typeof part === "object" && (part as z.ZodType)._zod) {
|
|
344
|
+
const innerType = zodTypeToTsTypeDef(part as z.ZodType);
|
|
345
|
+
return `\${${innerType}}`;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// 폴백
|
|
349
|
+
return `\${string}`;
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
return `\`${parts.join("")}\``;
|
|
353
|
+
}
|
|
354
|
+
case "file":
|
|
355
|
+
return "File";
|
|
356
|
+
default:
|
|
357
|
+
throw new Error(`처리되지 않은 ZodType ${zt.def.type}`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Zod 타입 인스턴스를 해당하는 Zod 코드 문자열로 변환합니다.
|
|
363
|
+
*/
|
|
364
|
+
export function zodTypeToZodCode(zt: z.ZodType): string {
|
|
365
|
+
switch (zt.def.type) {
|
|
366
|
+
case "string":
|
|
367
|
+
return "z.string()";
|
|
368
|
+
case "number":
|
|
369
|
+
return "z.number()";
|
|
370
|
+
case "bigint":
|
|
371
|
+
return "z.bigint()";
|
|
372
|
+
case "boolean":
|
|
373
|
+
return "z.boolean()";
|
|
374
|
+
case "date":
|
|
375
|
+
return "z.date()";
|
|
376
|
+
case "null":
|
|
377
|
+
return "z.null()";
|
|
378
|
+
case "undefined":
|
|
379
|
+
return "z.undefined()";
|
|
380
|
+
case "any":
|
|
381
|
+
return "z.any()";
|
|
382
|
+
case "unknown":
|
|
383
|
+
return "z.unknown()";
|
|
384
|
+
case "never":
|
|
385
|
+
return "z.never()";
|
|
386
|
+
case "nullable":
|
|
387
|
+
return `${zodTypeToZodCode((zt as AnyZodNullable).def.innerType)}.nullable()`;
|
|
388
|
+
case "default": {
|
|
389
|
+
const zDefaultDef = (zt as AnyZodDefault).def;
|
|
390
|
+
return `${zodTypeToZodCode(zDefaultDef.innerType)}.default(${zDefaultDef.defaultValue})`;
|
|
391
|
+
}
|
|
392
|
+
case "record": {
|
|
393
|
+
const zRecordDef = (zt as AnyZodRecord).def;
|
|
394
|
+
return `z.record(${zodTypeToZodCode(zRecordDef.keyType)}, ${zodTypeToZodCode(
|
|
395
|
+
zRecordDef.valueType,
|
|
396
|
+
)})`;
|
|
397
|
+
}
|
|
398
|
+
case "literal": {
|
|
399
|
+
const items = Array.from((zt as z.ZodLiteral<string | number>).values).map((value) => {
|
|
400
|
+
if (typeof value === "string") {
|
|
401
|
+
return `"${value}"`;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (value === null) {
|
|
405
|
+
return `null`;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (value === undefined) {
|
|
409
|
+
return `undefined`;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return `${value}`;
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
if (items.length === 1) {
|
|
416
|
+
return `z.literal(${items[0]})`;
|
|
417
|
+
}
|
|
418
|
+
return `z.literal([${items.join(", ")}])`;
|
|
419
|
+
}
|
|
420
|
+
case "union":
|
|
421
|
+
return `z.union([${(zt as AnyZodUnion).def.options
|
|
422
|
+
.map((option: z.ZodType) => zodTypeToZodCode(option))
|
|
423
|
+
.join(",")}])`;
|
|
424
|
+
case "enum":
|
|
425
|
+
// NOTE: z.enum(["A", "B"])도 z.enum({ A: "A", B: "B" })로 처리됨.
|
|
426
|
+
return `z.enum({${Object.entries((zt as z.ZodEnum).def.entries)
|
|
427
|
+
.map(([key, val]) => (typeof val === "string" ? `${key}: "${val}"` : `${key}: ${val}`))
|
|
428
|
+
.join(", ")}})`;
|
|
429
|
+
case "array":
|
|
430
|
+
return `z.array(${zodTypeToZodCode((zt as z.ZodArray<z.ZodType>).def.element)})`;
|
|
431
|
+
case "object": {
|
|
432
|
+
const shape = (zt as AnyZodObject).shape;
|
|
433
|
+
return [
|
|
434
|
+
"z.object({",
|
|
435
|
+
...Object.keys(shape).map((key) => `${key}: ${zodTypeToZodCode(shape[key])},`),
|
|
436
|
+
"})",
|
|
437
|
+
].join("\n");
|
|
438
|
+
}
|
|
439
|
+
case "optional":
|
|
440
|
+
return `${zodTypeToZodCode((zt as z.ZodOptional<z.ZodType>).def.innerType)}.optional()`;
|
|
441
|
+
case "file":
|
|
442
|
+
return `z.file()`;
|
|
443
|
+
case "template_literal": {
|
|
444
|
+
const def = (zt as AnyZodTemplateLiteral).def;
|
|
445
|
+
|
|
446
|
+
// 빈 template literal
|
|
447
|
+
if (!def.parts || def.parts.length === 0) {
|
|
448
|
+
return "z.templateLiteral([])";
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// 각 part를 Zod 코드 문자열로 변환
|
|
452
|
+
const parts = def.parts.map((part: unknown) => {
|
|
453
|
+
// 문자열 리터럴
|
|
454
|
+
if (typeof part === "string") {
|
|
455
|
+
return `"${part}"`;
|
|
456
|
+
}
|
|
457
|
+
// ZodType - 재귀적으로 변환
|
|
458
|
+
if (part && typeof part === "object" && (part as z.ZodType)._zod) {
|
|
459
|
+
return zodTypeToZodCode(part as z.ZodType);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// 폴백
|
|
463
|
+
return "z.string()";
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
return `z.templateLiteral([${parts.join(", ")}])`;
|
|
467
|
+
}
|
|
468
|
+
case "intersection": {
|
|
469
|
+
const zIntersectionDef = (zt as z.ZodIntersection<z.ZodType, z.ZodType>).def;
|
|
470
|
+
return `z.intersection(${zodTypeToZodCode(zIntersectionDef.left)}, ${zodTypeToZodCode(zIntersectionDef.right)})`;
|
|
471
|
+
}
|
|
472
|
+
default:
|
|
473
|
+
throw new Error(`처리되지 않은 ZodType ${zt.def.type}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
53
477
|
/**
|
|
54
478
|
* Zod 타입을 UI 렌더링에 사용할 수 있는 RenderingNode로 변환합니다.
|
|
55
479
|
* 재귀적으로 중첩된 타입들을 처리합니다.
|
|
56
480
|
*/
|
|
57
481
|
export function zodTypeToRenderingNode(
|
|
58
|
-
zodType: z.
|
|
59
|
-
baseKey: string = "root"
|
|
482
|
+
zodType: z.ZodTypeAny,
|
|
483
|
+
baseKey: string = "root",
|
|
60
484
|
): RenderingNode {
|
|
61
485
|
const def = {
|
|
62
486
|
name: baseKey,
|
|
@@ -75,7 +499,7 @@ export function zodTypeToRenderingNode(
|
|
|
75
499
|
children,
|
|
76
500
|
};
|
|
77
501
|
} else if (zodType instanceof z.ZodArray) {
|
|
78
|
-
const innerType = (zodType as z.ZodArray<z.
|
|
502
|
+
const innerType = (zodType as z.ZodArray<z.ZodTypeAny>).def.element;
|
|
79
503
|
if (innerType instanceof z.ZodString && baseKey.includes("images")) {
|
|
80
504
|
return {
|
|
81
505
|
...def,
|
|
@@ -88,25 +512,19 @@ export function zodTypeToRenderingNode(
|
|
|
88
512
|
element: zodTypeToRenderingNode(innerType, baseKey),
|
|
89
513
|
};
|
|
90
514
|
} else if (zodType instanceof z.ZodUnion) {
|
|
91
|
-
const optionNodes = (zodType as z.ZodUnion<z.ZodType[]>).def.options.map(
|
|
92
|
-
|
|
515
|
+
const optionNodes = (zodType as z.ZodUnion<z.ZodType[]>).def.options.map((opt) =>
|
|
516
|
+
zodTypeToRenderingNode(opt, baseKey),
|
|
93
517
|
);
|
|
94
518
|
// TODO: ZodUnion이 들어있는 경우 핸들링
|
|
95
519
|
return optionNodes[0];
|
|
96
520
|
} else if (zodType instanceof z.ZodOptional) {
|
|
97
521
|
return {
|
|
98
|
-
...zodTypeToRenderingNode(
|
|
99
|
-
(zodType as z.ZodOptional<z.ZodType>).def.innerType,
|
|
100
|
-
baseKey
|
|
101
|
-
),
|
|
522
|
+
...zodTypeToRenderingNode((zodType as z.ZodOptional<z.ZodType>).def.innerType, baseKey),
|
|
102
523
|
optional: true,
|
|
103
524
|
};
|
|
104
525
|
} else if (zodType instanceof z.ZodNullable) {
|
|
105
526
|
return {
|
|
106
|
-
...zodTypeToRenderingNode(
|
|
107
|
-
(zodType as z.ZodNullable<z.ZodType>).def.innerType,
|
|
108
|
-
baseKey
|
|
109
|
-
),
|
|
527
|
+
...zodTypeToRenderingNode((zodType as z.ZodNullable<z.ZodType>).def.innerType, baseKey),
|
|
110
528
|
nullable: true,
|
|
111
529
|
};
|
|
112
530
|
} else {
|
|
@@ -120,10 +538,7 @@ export function zodTypeToRenderingNode(
|
|
|
120
538
|
/**
|
|
121
539
|
* Zod 타입과 키 이름으로부터 적절한 RenderType을 결정합니다.
|
|
122
540
|
*/
|
|
123
|
-
function resolveRenderType(
|
|
124
|
-
key: string,
|
|
125
|
-
zodType: z.ZodTypeAny
|
|
126
|
-
): RenderingNode["renderType"] {
|
|
541
|
+
function resolveRenderType(key: string, zodType: z.ZodTypeAny): RenderingNode["renderType"] {
|
|
127
542
|
if (zodType instanceof z.ZodDate) {
|
|
128
543
|
return "datetime";
|
|
129
544
|
} else if (zodType instanceof z.ZodString) {
|
|
@@ -160,60 +575,3 @@ function resolveRenderType(
|
|
|
160
575
|
throw new Error(`타입 파싱 불가 ${key} ${zodType.def.type}`);
|
|
161
576
|
}
|
|
162
577
|
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* EntityProp을 Zod 타입으로 변환합니다.
|
|
166
|
-
* 각 prop의 타입에 따라 적절한 Zod validator를 생성합니다.
|
|
167
|
-
*/
|
|
168
|
-
export async function propToZodType(prop: EntityProp): Promise<z.ZodTypeAny> {
|
|
169
|
-
let zodType: z.ZodTypeAny = z.unknown();
|
|
170
|
-
if (isIntegerProp(prop)) {
|
|
171
|
-
zodType = z.number().int();
|
|
172
|
-
} else if (isBigIntegerProp(prop)) {
|
|
173
|
-
zodType = z.bigint();
|
|
174
|
-
} else if (isTextProp(prop)) {
|
|
175
|
-
zodType = z.string().max(getTextTypeLength(prop.textType));
|
|
176
|
-
} else if (isEnumProp(prop)) {
|
|
177
|
-
zodType = await getZodTypeById(prop.id);
|
|
178
|
-
} else if (isStringProp(prop)) {
|
|
179
|
-
zodType = z.string().max(prop.length);
|
|
180
|
-
} else if (isFloatProp(prop) || isDoubleProp(prop)) {
|
|
181
|
-
zodType = z.number();
|
|
182
|
-
} else if (isDecimalProp(prop)) {
|
|
183
|
-
zodType = z.string();
|
|
184
|
-
} else if (isBooleanProp(prop)) {
|
|
185
|
-
zodType = z.boolean();
|
|
186
|
-
} else if (isDateProp(prop)) {
|
|
187
|
-
zodType = z.string().length(10);
|
|
188
|
-
} else if (isTimeProp(prop)) {
|
|
189
|
-
zodType = z.string().length(8);
|
|
190
|
-
} else if (isDateTimeProp(prop)) {
|
|
191
|
-
zodType = z.date();
|
|
192
|
-
} else if (isTimestampProp(prop)) {
|
|
193
|
-
zodType = z.date();
|
|
194
|
-
} else if (isJsonProp(prop)) {
|
|
195
|
-
zodType = await getZodTypeById(prop.id);
|
|
196
|
-
} else if (isUuidProp(prop)) {
|
|
197
|
-
zodType = z.uuid();
|
|
198
|
-
} else if (isVirtualProp(prop)) {
|
|
199
|
-
zodType = await getZodTypeById(prop.id);
|
|
200
|
-
} else if (isRelationProp(prop)) {
|
|
201
|
-
if (
|
|
202
|
-
isBelongsToOneRelationProp(prop) ||
|
|
203
|
-
(isOneToOneRelationProp(prop) && prop.hasJoinColumn)
|
|
204
|
-
) {
|
|
205
|
-
zodType = z.number().int();
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
throw new Error(`prop을 zodType으로 변환하는데 실패 ${prop}}`);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if ((prop as { unsigned?: boolean }).unsigned) {
|
|
212
|
-
zodType = (zodType as z.ZodNumber).nonnegative();
|
|
213
|
-
}
|
|
214
|
-
if (prop.nullable) {
|
|
215
|
-
zodType = zodType.nullable();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return zodType;
|
|
219
|
-
}
|