velocious 1.0.449 → 1.0.451
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/application.js +4 -4
- package/build/authorization/ability.js +8 -8
- package/build/authorization/base-resource.js +4 -4
- package/build/background-jobs/cron-expression.js +1 -1
- package/build/background-jobs/forked-runner-child.js +1 -1
- package/build/background-jobs/job-registry.js +1 -1
- package/build/background-jobs/job-runner.js +1 -1
- package/build/background-jobs/job.js +1 -1
- package/build/background-jobs/json-socket.js +4 -4
- package/build/background-jobs/main.js +21 -21
- package/build/background-jobs/scheduler.js +7 -7
- package/build/background-jobs/store.js +7 -7
- package/build/background-jobs/web/controller.js +2 -2
- package/build/background-jobs/worker.js +12 -12
- package/build/beacon/client.js +11 -8
- package/build/beacon/in-process-broker.js +2 -2
- package/build/beacon/in-process-client.js +2 -2
- package/build/beacon/server.js +3 -3
- package/build/cli/browser-cli.js +1 -1
- package/build/cli/commands/db/base-command.js +2 -2
- package/build/cli/index.js +2 -2
- package/build/cli/tenant-database-command-helper.js +3 -3
- package/build/cli/use-browser-cli.js +1 -1
- package/build/configuration-types.js +3 -1
- package/build/configuration.js +38 -38
- package/build/controller.js +8 -8
- package/build/current-configuration.js +1 -1
- package/build/database/annotations-async-hooks.js +2 -2
- package/build/database/annotations.js +3 -3
- package/build/database/drivers/base-column.js +1 -1
- package/build/database/drivers/base-foreign-key.js +1 -1
- package/build/database/drivers/base-table.js +1 -1
- package/build/database/drivers/base.js +10 -10
- package/build/database/drivers/mssql/index.js +1 -1
- package/build/database/drivers/mssql/table.js +1 -1
- package/build/database/drivers/mysql/index.js +3 -3
- package/build/database/drivers/mysql/query.js +1 -1
- package/build/database/drivers/mysql/table.js +1 -1
- package/build/database/drivers/pgsql/index.js +2 -2
- package/build/database/drivers/sqlite/base.js +16 -16
- package/build/database/drivers/sqlite/index.js +11 -11
- package/build/database/drivers/sqlite/index.native.js +1 -1
- package/build/database/drivers/sqlite/index.web.js +3 -3
- package/build/database/drivers/sqlite/query.js +1 -1
- package/build/database/drivers/sqlite/query.web.js +1 -1
- package/build/database/drivers/sqlite/sql/alter-table.js +2 -2
- package/build/database/drivers/sqlite/table.js +1 -1
- package/build/database/migrator/files-finder.js +1 -1
- package/build/database/migrator.js +6 -6
- package/build/database/pool/async-tracked-multi-connection.js +27 -27
- package/build/database/pool/base-methods-forward.js +4 -4
- package/build/database/pool/base.js +8 -8
- package/build/database/query/from-base.js +1 -1
- package/build/database/query/index.js +10 -10
- package/build/database/query/join-object.js +3 -3
- package/build/database/query/model-class-query.js +39 -39
- package/build/database/query/preloader/belongs-to.js +22 -22
- package/build/database/query/preloader/has-many.js +20 -20
- package/build/database/query/preloader/has-one.js +8 -8
- package/build/database/query/preloader/selection.js +3 -3
- package/build/database/query/preloader.js +8 -8
- package/build/database/query/query-data.js +9 -9
- package/build/database/query/where-model-class-hash.js +7 -7
- package/build/database/query/with-count.js +9 -9
- package/build/database/record/acts-as-list.js +15 -15
- package/build/database/record/attachments/handle.js +2 -2
- package/build/database/record/attachments/normalize-input.js +12 -12
- package/build/database/record/attachments/storage-drivers/s3.js +6 -6
- package/build/database/record/attachments/store.js +13 -13
- package/build/database/record/index.js +115 -121
- package/build/database/record/instance-relationships/base.js +11 -11
- package/build/database/record/instance-relationships/belongs-to.js +3 -3
- package/build/database/record/instance-relationships/has-many.js +8 -8
- package/build/database/record/instance-relationships/has-one.js +7 -7
- package/build/database/record/relationships/base.js +2 -2
- package/build/database/record/state-machine.js +7 -7
- package/build/database/record/validators/presence.js +1 -1
- package/build/database/record/validators/uniqueness.js +5 -5
- package/build/database/table-data/index.js +4 -4
- package/build/environment-handlers/base.js +2 -2
- package/build/environment-handlers/browser.js +7 -7
- package/build/environment-handlers/node/cli/commands/cli-command-context.js +1 -1
- package/build/environment-handlers/node/cli/commands/console.js +4 -4
- package/build/environment-handlers/node/cli/commands/db/schema/dump.js +1 -1
- package/build/environment-handlers/node/cli/commands/db/schema/load.js +3 -3
- package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +836 -60
- package/build/environment-handlers/node.js +6 -6
- package/build/frontend-model-controller.js +81 -82
- package/build/frontend-model-resource/base-resource.js +78 -115
- package/build/frontend-models/base.js +162 -149
- package/build/frontend-models/clear-pending-debounced-callback.js +1 -1
- package/build/frontend-models/event-hook-models.js +2 -2
- package/build/frontend-models/outgoing-event-buffer.js +2 -2
- package/build/frontend-models/preloader.js +5 -5
- package/build/frontend-models/query.js +43 -38
- package/build/frontend-models/resource-definition.js +6 -6
- package/build/frontend-models/transport-serialization.js +11 -11
- package/build/frontend-models/use-destroyed-event.js +10 -10
- package/build/frontend-models/use-model-class-event.js +11 -11
- package/build/frontend-models/use-updated-event.js +11 -11
- package/build/frontend-models/websocket-channel.js +26 -17
- package/build/frontend-models/websocket-publishers.js +9 -9
- package/build/http-client/response.js +2 -2
- package/build/http-server/client/index.js +8 -8
- package/build/http-server/client/params-to-object.js +10 -10
- package/build/http-server/client/request-buffer/form-data-part.js +2 -2
- package/build/http-server/client/request-buffer/index.js +8 -8
- package/build/http-server/client/request-parser.js +3 -3
- package/build/http-server/client/request-runner.js +6 -6
- package/build/http-server/client/request-timing.js +5 -5
- package/build/http-server/client/request.js +1 -1
- package/build/http-server/client/response.js +5 -5
- package/build/http-server/client/websocket-request.js +4 -4
- package/build/http-server/client/websocket-session.js +18 -18
- package/build/http-server/development-reloader.js +5 -5
- package/build/http-server/index.js +12 -12
- package/build/http-server/remote-address.js +4 -4
- package/build/http-server/server-client.js +3 -3
- package/build/http-server/server-lock.js +4 -4
- package/build/http-server/websocket-channel-subscribers.js +3 -3
- package/build/http-server/websocket-channel.js +1 -1
- package/build/http-server/websocket-connection.js +1 -1
- package/build/http-server/websocket-event-log-store.js +6 -6
- package/build/http-server/websocket-events-host.js +2 -2
- package/build/http-server/worker-handler/in-process.js +7 -7
- package/build/http-server/worker-handler/index.js +4 -4
- package/build/http-server/worker-handler/worker-thread.js +3 -3
- package/build/logger/outputs/array-output.js +3 -3
- package/build/logger/outputs/console-output.js +1 -1
- package/build/logger/outputs/file-output.js +4 -4
- package/build/logger/outputs/stdout-output.js +1 -1
- package/build/logger.js +10 -10
- package/build/mailer/backends/smtp.js +3 -3
- package/build/mailer/base.js +8 -8
- package/build/mailer/delivery.js +4 -4
- package/build/plugins/sqljs-wasm-route-controller.js +1 -1
- package/build/routes/base-route.js +6 -6
- package/build/routes/basic-route.js +1 -1
- package/build/routes/hooks/frontend-model-command-route-hook.js +1 -1
- package/build/routes/index.js +1 -1
- package/build/routes/plugin-routes.js +1 -1
- package/build/routes/resolver.js +11 -11
- package/build/routes/resource-route.js +1 -1
- package/build/src/application.d.ts +3 -3
- package/build/src/application.d.ts.map +1 -1
- package/build/src/application.js +5 -5
- package/build/src/authorization/ability.d.ts +7 -7
- package/build/src/authorization/ability.d.ts.map +1 -1
- package/build/src/authorization/ability.js +9 -9
- package/build/src/authorization/base-resource.d.ts +1 -1
- package/build/src/authorization/base-resource.d.ts.map +1 -1
- package/build/src/authorization/base-resource.js +5 -5
- package/build/src/background-jobs/cron-expression.js +2 -2
- package/build/src/background-jobs/forked-runner-child.js +2 -2
- package/build/src/background-jobs/job-registry.d.ts +1 -1
- package/build/src/background-jobs/job-registry.d.ts.map +1 -1
- package/build/src/background-jobs/job-registry.js +2 -2
- package/build/src/background-jobs/job-runner.js +2 -2
- package/build/src/background-jobs/job.js +2 -2
- package/build/src/background-jobs/json-socket.d.ts +4 -4
- package/build/src/background-jobs/json-socket.d.ts.map +1 -1
- package/build/src/background-jobs/json-socket.js +5 -5
- package/build/src/background-jobs/main.d.ts +18 -18
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +22 -22
- package/build/src/background-jobs/scheduler.d.ts +5 -5
- package/build/src/background-jobs/scheduler.d.ts.map +1 -1
- package/build/src/background-jobs/scheduler.js +8 -8
- package/build/src/background-jobs/store.js +8 -8
- package/build/src/background-jobs/web/controller.js +3 -3
- package/build/src/background-jobs/worker.d.ts +6 -6
- package/build/src/background-jobs/worker.d.ts.map +1 -1
- package/build/src/background-jobs/worker.js +13 -13
- package/build/src/beacon/client.d.ts +4 -4
- package/build/src/beacon/client.d.ts.map +1 -1
- package/build/src/beacon/client.js +12 -9
- package/build/src/beacon/in-process-broker.d.ts.map +1 -1
- package/build/src/beacon/in-process-broker.js +3 -3
- package/build/src/beacon/in-process-client.d.ts +1 -1
- package/build/src/beacon/in-process-client.d.ts.map +1 -1
- package/build/src/beacon/in-process-client.js +3 -3
- package/build/src/beacon/server.d.ts +2 -2
- package/build/src/beacon/server.d.ts.map +1 -1
- package/build/src/beacon/server.js +4 -4
- package/build/src/cli/browser-cli.js +2 -2
- package/build/src/cli/commands/db/base-command.d.ts +2 -2
- package/build/src/cli/commands/db/base-command.d.ts.map +1 -1
- package/build/src/cli/commands/db/base-command.js +3 -3
- package/build/src/cli/index.js +3 -3
- package/build/src/cli/tenant-database-command-helper.d.ts +1 -1
- package/build/src/cli/tenant-database-command-helper.d.ts.map +1 -1
- package/build/src/cli/tenant-database-command-helper.js +4 -4
- package/build/src/cli/use-browser-cli.js +2 -2
- package/build/src/configuration-types.d.ts +12 -2
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +4 -2
- package/build/src/configuration.d.ts +14 -14
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +39 -39
- package/build/src/controller.js +10 -10
- package/build/src/current-configuration.js +2 -2
- package/build/src/database/annotations-async-hooks.js +3 -3
- package/build/src/database/annotations.d.ts.map +1 -1
- package/build/src/database/annotations.js +4 -4
- package/build/src/database/drivers/base-column.d.ts +1 -1
- package/build/src/database/drivers/base-column.d.ts.map +1 -1
- package/build/src/database/drivers/base-column.js +2 -2
- package/build/src/database/drivers/base-foreign-key.d.ts +1 -1
- package/build/src/database/drivers/base-foreign-key.d.ts.map +1 -1
- package/build/src/database/drivers/base-foreign-key.js +2 -2
- package/build/src/database/drivers/base-table.d.ts +1 -1
- package/build/src/database/drivers/base-table.d.ts.map +1 -1
- package/build/src/database/drivers/base-table.js +2 -2
- package/build/src/database/drivers/base.d.ts +6 -6
- package/build/src/database/drivers/base.d.ts.map +1 -1
- package/build/src/database/drivers/base.js +11 -11
- package/build/src/database/drivers/mssql/index.js +2 -2
- package/build/src/database/drivers/mssql/table.js +2 -2
- package/build/src/database/drivers/mysql/index.js +4 -4
- package/build/src/database/drivers/mysql/query.js +2 -2
- package/build/src/database/drivers/mysql/table.js +2 -2
- package/build/src/database/drivers/pgsql/index.js +3 -3
- package/build/src/database/drivers/sqlite/base.d.ts +3 -3
- package/build/src/database/drivers/sqlite/base.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/base.js +17 -17
- package/build/src/database/drivers/sqlite/index.d.ts +4 -4
- package/build/src/database/drivers/sqlite/index.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.js +12 -12
- package/build/src/database/drivers/sqlite/index.native.js +2 -2
- package/build/src/database/drivers/sqlite/index.web.d.ts +2 -2
- package/build/src/database/drivers/sqlite/index.web.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.web.js +4 -4
- package/build/src/database/drivers/sqlite/query.js +2 -2
- package/build/src/database/drivers/sqlite/query.web.js +2 -2
- package/build/src/database/drivers/sqlite/sql/alter-table.js +3 -3
- package/build/src/database/drivers/sqlite/table.js +2 -2
- package/build/src/database/migrator/files-finder.js +2 -2
- package/build/src/database/migrator.d.ts +1 -1
- package/build/src/database/migrator.d.ts.map +1 -1
- package/build/src/database/migrator.js +7 -7
- package/build/src/database/pool/async-tracked-multi-connection.d.ts +9 -9
- package/build/src/database/pool/async-tracked-multi-connection.d.ts.map +1 -1
- package/build/src/database/pool/async-tracked-multi-connection.js +28 -28
- package/build/src/database/pool/base-methods-forward.js +7 -7
- package/build/src/database/pool/base.d.ts +1 -1
- package/build/src/database/pool/base.d.ts.map +1 -1
- package/build/src/database/pool/base.js +9 -9
- package/build/src/database/query/from-base.d.ts +1 -1
- package/build/src/database/query/from-base.d.ts.map +1 -1
- package/build/src/database/query/from-base.js +2 -2
- package/build/src/database/query/index.d.ts +4 -4
- package/build/src/database/query/index.d.ts.map +1 -1
- package/build/src/database/query/index.js +11 -11
- package/build/src/database/query/join-object.js +4 -4
- package/build/src/database/query/model-class-query.d.ts +4 -4
- package/build/src/database/query/model-class-query.d.ts.map +1 -1
- package/build/src/database/query/model-class-query.js +40 -40
- package/build/src/database/query/preloader/belongs-to.js +23 -23
- package/build/src/database/query/preloader/has-many.js +21 -21
- package/build/src/database/query/preloader/has-one.js +9 -9
- package/build/src/database/query/preloader/selection.js +4 -4
- package/build/src/database/query/preloader.js +9 -9
- package/build/src/database/query/query-data.js +10 -10
- package/build/src/database/query/where-model-class-hash.js +8 -8
- package/build/src/database/query/with-count.js +10 -10
- package/build/src/database/record/acts-as-list.js +20 -20
- package/build/src/database/record/attachments/handle.d.ts +1 -1
- package/build/src/database/record/attachments/handle.d.ts.map +1 -1
- package/build/src/database/record/attachments/handle.js +3 -3
- package/build/src/database/record/attachments/normalize-input.js +15 -15
- package/build/src/database/record/attachments/storage-drivers/s3.js +7 -7
- package/build/src/database/record/attachments/store.d.ts +2 -2
- package/build/src/database/record/attachments/store.d.ts.map +1 -1
- package/build/src/database/record/attachments/store.js +14 -14
- package/build/src/database/record/index.d.ts +18 -25
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +135 -141
- package/build/src/database/record/instance-relationships/base.d.ts +3 -3
- package/build/src/database/record/instance-relationships/base.d.ts.map +1 -1
- package/build/src/database/record/instance-relationships/base.js +13 -13
- package/build/src/database/record/instance-relationships/belongs-to.js +4 -4
- package/build/src/database/record/instance-relationships/has-many.js +9 -9
- package/build/src/database/record/instance-relationships/has-one.d.ts +1 -1
- package/build/src/database/record/instance-relationships/has-one.d.ts.map +1 -1
- package/build/src/database/record/instance-relationships/has-one.js +8 -8
- package/build/src/database/record/relationships/base.js +4 -4
- package/build/src/database/record/state-machine.js +8 -8
- package/build/src/database/record/validators/presence.js +2 -2
- package/build/src/database/record/validators/uniqueness.js +6 -6
- package/build/src/database/table-data/index.d.ts +4 -4
- package/build/src/database/table-data/index.d.ts.map +1 -1
- package/build/src/database/table-data/index.js +5 -5
- package/build/src/environment-handlers/base.js +3 -3
- package/build/src/environment-handlers/browser.d.ts +3 -3
- package/build/src/environment-handlers/browser.d.ts.map +1 -1
- package/build/src/environment-handlers/browser.js +8 -8
- package/build/src/environment-handlers/node/cli/commands/cli-command-context.js +2 -2
- package/build/src/environment-handlers/node/cli/commands/console.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/console.js +5 -5
- package/build/src/environment-handlers/node/cli/commands/db/schema/dump.d.ts +1 -1
- package/build/src/environment-handlers/node/cli/commands/db/schema/dump.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/db/schema/dump.js +2 -2
- package/build/src/environment-handlers/node/cli/commands/db/schema/load.d.ts +1 -1
- package/build/src/environment-handlers/node/cli/commands/db/schema/load.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/db/schema/load.js +4 -4
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +285 -12
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +712 -61
- package/build/src/environment-handlers/node.d.ts +2 -2
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +7 -7
- package/build/src/frontend-model-controller.d.ts +5 -6
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +88 -89
- package/build/src/frontend-model-resource/base-resource.d.ts +36 -27
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +67 -120
- package/build/src/frontend-models/base.d.ts +67 -59
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +171 -158
- package/build/src/frontend-models/clear-pending-debounced-callback.js +2 -2
- package/build/src/frontend-models/event-hook-models.d.ts.map +1 -1
- package/build/src/frontend-models/event-hook-models.js +3 -3
- package/build/src/frontend-models/outgoing-event-buffer.d.ts +1 -1
- package/build/src/frontend-models/outgoing-event-buffer.d.ts.map +1 -1
- package/build/src/frontend-models/outgoing-event-buffer.js +3 -3
- package/build/src/frontend-models/preloader.js +6 -6
- package/build/src/frontend-models/query.d.ts +16 -8
- package/build/src/frontend-models/query.d.ts.map +1 -1
- package/build/src/frontend-models/query.js +43 -39
- package/build/src/frontend-models/resource-definition.js +7 -7
- package/build/src/frontend-models/transport-serialization.js +12 -12
- package/build/src/frontend-models/use-destroyed-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-destroyed-event.js +11 -11
- package/build/src/frontend-models/use-model-class-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-model-class-event.js +12 -12
- package/build/src/frontend-models/use-updated-event.d.ts.map +1 -1
- package/build/src/frontend-models/use-updated-event.js +12 -12
- package/build/src/frontend-models/websocket-channel.d.ts +6 -1
- package/build/src/frontend-models/websocket-channel.d.ts.map +1 -1
- package/build/src/frontend-models/websocket-channel.js +26 -18
- package/build/src/frontend-models/websocket-publishers.js +11 -11
- package/build/src/http-client/response.d.ts +2 -2
- package/build/src/http-client/response.d.ts.map +1 -1
- package/build/src/http-client/response.js +3 -3
- package/build/src/http-server/client/index.d.ts +1 -1
- package/build/src/http-server/client/index.d.ts.map +1 -1
- package/build/src/http-server/client/index.js +9 -9
- package/build/src/http-server/client/params-to-object.js +11 -11
- package/build/src/http-server/client/request-buffer/form-data-part.d.ts +2 -2
- package/build/src/http-server/client/request-buffer/form-data-part.d.ts.map +1 -1
- package/build/src/http-server/client/request-buffer/form-data-part.js +3 -3
- package/build/src/http-server/client/request-buffer/index.d.ts +4 -4
- package/build/src/http-server/client/request-buffer/index.d.ts.map +1 -1
- package/build/src/http-server/client/request-buffer/index.js +9 -9
- package/build/src/http-server/client/request-parser.d.ts +1 -1
- package/build/src/http-server/client/request-parser.d.ts.map +1 -1
- package/build/src/http-server/client/request-parser.js +4 -4
- package/build/src/http-server/client/request-runner.js +7 -7
- package/build/src/http-server/client/request-timing.d.ts +5 -5
- package/build/src/http-server/client/request-timing.d.ts.map +1 -1
- package/build/src/http-server/client/request-timing.js +6 -6
- package/build/src/http-server/client/request.js +2 -2
- package/build/src/http-server/client/response.d.ts +3 -3
- package/build/src/http-server/client/response.d.ts.map +1 -1
- package/build/src/http-server/client/response.js +6 -6
- package/build/src/http-server/client/websocket-request.d.ts +3 -3
- package/build/src/http-server/client/websocket-request.d.ts.map +1 -1
- package/build/src/http-server/client/websocket-request.js +5 -5
- package/build/src/http-server/client/websocket-session.d.ts +6 -6
- package/build/src/http-server/client/websocket-session.d.ts.map +1 -1
- package/build/src/http-server/client/websocket-session.js +19 -19
- package/build/src/http-server/development-reloader.d.ts +3 -3
- package/build/src/http-server/development-reloader.d.ts.map +1 -1
- package/build/src/http-server/development-reloader.js +6 -6
- package/build/src/http-server/index.d.ts +7 -7
- package/build/src/http-server/index.d.ts.map +1 -1
- package/build/src/http-server/index.js +13 -13
- package/build/src/http-server/remote-address.js +6 -6
- package/build/src/http-server/server-client.js +4 -4
- package/build/src/http-server/server-lock.js +5 -5
- package/build/src/http-server/websocket-channel-subscribers.d.ts +1 -1
- package/build/src/http-server/websocket-channel-subscribers.d.ts.map +1 -1
- package/build/src/http-server/websocket-channel-subscribers.js +4 -4
- package/build/src/http-server/websocket-channel.d.ts +1 -1
- package/build/src/http-server/websocket-channel.d.ts.map +1 -1
- package/build/src/http-server/websocket-channel.js +2 -2
- package/build/src/http-server/websocket-connection.d.ts +1 -1
- package/build/src/http-server/websocket-connection.d.ts.map +1 -1
- package/build/src/http-server/websocket-connection.js +2 -2
- package/build/src/http-server/websocket-event-log-store.d.ts +1 -1
- package/build/src/http-server/websocket-event-log-store.d.ts.map +1 -1
- package/build/src/http-server/websocket-event-log-store.js +7 -7
- package/build/src/http-server/websocket-events-host.d.ts +1 -1
- package/build/src/http-server/websocket-events-host.d.ts.map +1 -1
- package/build/src/http-server/websocket-events-host.js +3 -3
- package/build/src/http-server/worker-handler/in-process.d.ts +3 -3
- package/build/src/http-server/worker-handler/in-process.d.ts.map +1 -1
- package/build/src/http-server/worker-handler/in-process.js +9 -9
- package/build/src/http-server/worker-handler/index.d.ts +4 -4
- package/build/src/http-server/worker-handler/index.d.ts.map +1 -1
- package/build/src/http-server/worker-handler/index.js +5 -5
- package/build/src/http-server/worker-handler/worker-thread.d.ts +2 -2
- package/build/src/http-server/worker-handler/worker-thread.d.ts.map +1 -1
- package/build/src/http-server/worker-handler/worker-thread.js +4 -4
- package/build/src/logger/outputs/array-output.d.ts +3 -3
- package/build/src/logger/outputs/array-output.d.ts.map +1 -1
- package/build/src/logger/outputs/array-output.js +4 -4
- package/build/src/logger/outputs/console-output.d.ts +1 -1
- package/build/src/logger/outputs/console-output.d.ts.map +1 -1
- package/build/src/logger/outputs/console-output.js +2 -2
- package/build/src/logger/outputs/file-output.d.ts +4 -4
- package/build/src/logger/outputs/file-output.d.ts.map +1 -1
- package/build/src/logger/outputs/file-output.js +5 -5
- package/build/src/logger/outputs/stdout-output.d.ts.map +1 -1
- package/build/src/logger/outputs/stdout-output.js +2 -2
- package/build/src/logger.d.ts.map +1 -1
- package/build/src/logger.js +11 -11
- package/build/src/mailer/backends/smtp.d.ts.map +1 -1
- package/build/src/mailer/backends/smtp.js +5 -5
- package/build/src/mailer/base.js +11 -11
- package/build/src/mailer/delivery.d.ts +3 -3
- package/build/src/mailer/delivery.d.ts.map +1 -1
- package/build/src/mailer/delivery.js +5 -5
- package/build/src/plugins/sqljs-wasm-route-controller.js +2 -2
- package/build/src/routes/base-route.d.ts +6 -6
- package/build/src/routes/base-route.d.ts.map +1 -1
- package/build/src/routes/base-route.js +7 -7
- package/build/src/routes/basic-route.js +2 -2
- package/build/src/routes/hooks/frontend-model-command-route-hook.js +2 -2
- package/build/src/routes/index.js +2 -2
- package/build/src/routes/plugin-routes.js +2 -2
- package/build/src/routes/resolver.d.ts +1 -1
- package/build/src/routes/resolver.d.ts.map +1 -1
- package/build/src/routes/resolver.js +13 -13
- package/build/src/routes/resource-route.d.ts +1 -1
- package/build/src/routes/resource-route.d.ts.map +1 -1
- package/build/src/routes/resource-route.js +2 -2
- package/build/src/testing/browser-frontend-model-event-hook-scenarios.d.ts.map +1 -1
- package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +8 -8
- package/build/src/testing/expect-utils.js +13 -13
- package/build/src/testing/expect.d.ts +1 -1
- package/build/src/testing/expect.d.ts.map +1 -1
- package/build/src/testing/expect.js +9 -9
- package/build/src/testing/test-files-finder.d.ts +8 -8
- package/build/src/testing/test-files-finder.d.ts.map +1 -1
- package/build/src/testing/test-files-finder.js +9 -9
- package/build/src/testing/test-filter-parser.js +3 -3
- package/build/src/testing/test-runner.d.ts +2 -2
- package/build/src/testing/test-runner.d.ts.map +1 -1
- package/build/src/testing/test-runner.js +17 -17
- package/build/src/testing/test-suite-splitter.js +2 -2
- package/build/src/testing/test.d.ts +2 -2
- package/build/src/testing/test.d.ts.map +1 -1
- package/build/src/testing/test.js +16 -16
- package/build/src/utils/backtrace-cleaner.d.ts +1 -1
- package/build/src/utils/backtrace-cleaner.d.ts.map +1 -1
- package/build/src/utils/backtrace-cleaner.js +2 -2
- package/build/src/utils/format-value.js +2 -2
- package/build/src/utils/model-scope.js +2 -2
- package/build/src/utils/ransack.js +27 -27
- package/build/src/utils/with-tracked-stack-async-hooks.js +8 -8
- package/build/src/utils/with-tracked-stack.js +4 -4
- package/build/testing/browser-frontend-model-event-hook-scenarios.js +7 -7
- package/build/testing/expect-utils.js +11 -11
- package/build/testing/expect.js +7 -7
- package/build/testing/test-files-finder.js +8 -8
- package/build/testing/test-filter-parser.js +2 -2
- package/build/testing/test-runner.js +16 -16
- package/build/testing/test-suite-splitter.js +1 -1
- package/build/testing/test.js +15 -15
- package/build/utils/backtrace-cleaner.js +1 -1
- package/build/utils/format-value.js +1 -1
- package/build/utils/model-scope.js +1 -1
- package/build/utils/ransack.js +26 -26
- package/build/utils/with-tracked-stack-async-hooks.js +7 -7
- package/build/utils/with-tracked-stack.js +3 -3
- package/package.json +2 -1
- package/src/application.js +4 -4
- package/src/authorization/ability.js +8 -8
- package/src/authorization/base-resource.js +4 -4
- package/src/background-jobs/cron-expression.js +1 -1
- package/src/background-jobs/forked-runner-child.js +1 -1
- package/src/background-jobs/job-registry.js +1 -1
- package/src/background-jobs/job-runner.js +1 -1
- package/src/background-jobs/job.js +1 -1
- package/src/background-jobs/json-socket.js +4 -4
- package/src/background-jobs/main.js +21 -21
- package/src/background-jobs/scheduler.js +7 -7
- package/src/background-jobs/store.js +7 -7
- package/src/background-jobs/web/controller.js +2 -2
- package/src/background-jobs/worker.js +12 -12
- package/src/beacon/client.js +11 -8
- package/src/beacon/in-process-broker.js +2 -2
- package/src/beacon/in-process-client.js +2 -2
- package/src/beacon/server.js +3 -3
- package/src/cli/browser-cli.js +1 -1
- package/src/cli/commands/db/base-command.js +2 -2
- package/src/cli/index.js +2 -2
- package/src/cli/tenant-database-command-helper.js +3 -3
- package/src/cli/use-browser-cli.js +1 -1
- package/src/configuration-types.js +3 -1
- package/src/configuration.js +38 -38
- package/src/controller.js +8 -8
- package/src/current-configuration.js +1 -1
- package/src/database/annotations-async-hooks.js +2 -2
- package/src/database/annotations.js +3 -3
- package/src/database/drivers/base-column.js +1 -1
- package/src/database/drivers/base-foreign-key.js +1 -1
- package/src/database/drivers/base-table.js +1 -1
- package/src/database/drivers/base.js +10 -10
- package/src/database/drivers/mssql/index.js +1 -1
- package/src/database/drivers/mssql/table.js +1 -1
- package/src/database/drivers/mysql/index.js +3 -3
- package/src/database/drivers/mysql/query.js +1 -1
- package/src/database/drivers/mysql/table.js +1 -1
- package/src/database/drivers/pgsql/index.js +2 -2
- package/src/database/drivers/sqlite/base.js +16 -16
- package/src/database/drivers/sqlite/index.js +11 -11
- package/src/database/drivers/sqlite/index.native.js +1 -1
- package/src/database/drivers/sqlite/index.web.js +3 -3
- package/src/database/drivers/sqlite/query.js +1 -1
- package/src/database/drivers/sqlite/query.web.js +1 -1
- package/src/database/drivers/sqlite/sql/alter-table.js +2 -2
- package/src/database/drivers/sqlite/table.js +1 -1
- package/src/database/migrator/files-finder.js +1 -1
- package/src/database/migrator.js +6 -6
- package/src/database/pool/async-tracked-multi-connection.js +27 -27
- package/src/database/pool/base-methods-forward.js +4 -4
- package/src/database/pool/base.js +8 -8
- package/src/database/query/from-base.js +1 -1
- package/src/database/query/index.js +10 -10
- package/src/database/query/join-object.js +3 -3
- package/src/database/query/model-class-query.js +39 -39
- package/src/database/query/preloader/belongs-to.js +22 -22
- package/src/database/query/preloader/has-many.js +20 -20
- package/src/database/query/preloader/has-one.js +8 -8
- package/src/database/query/preloader/selection.js +3 -3
- package/src/database/query/preloader.js +8 -8
- package/src/database/query/query-data.js +9 -9
- package/src/database/query/where-model-class-hash.js +7 -7
- package/src/database/query/with-count.js +9 -9
- package/src/database/record/acts-as-list.js +15 -15
- package/src/database/record/attachments/handle.js +2 -2
- package/src/database/record/attachments/normalize-input.js +12 -12
- package/src/database/record/attachments/storage-drivers/s3.js +6 -6
- package/src/database/record/attachments/store.js +13 -13
- package/src/database/record/index.js +115 -121
- package/src/database/record/instance-relationships/base.js +11 -11
- package/src/database/record/instance-relationships/belongs-to.js +3 -3
- package/src/database/record/instance-relationships/has-many.js +8 -8
- package/src/database/record/instance-relationships/has-one.js +7 -7
- package/src/database/record/relationships/base.js +2 -2
- package/src/database/record/state-machine.js +7 -7
- package/src/database/record/validators/presence.js +1 -1
- package/src/database/record/validators/uniqueness.js +5 -5
- package/src/database/table-data/index.js +4 -4
- package/src/environment-handlers/base.js +2 -2
- package/src/environment-handlers/browser.js +7 -7
- package/src/environment-handlers/node/cli/commands/cli-command-context.js +1 -1
- package/src/environment-handlers/node/cli/commands/console.js +4 -4
- package/src/environment-handlers/node/cli/commands/db/schema/dump.js +1 -1
- package/src/environment-handlers/node/cli/commands/db/schema/load.js +3 -3
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +836 -60
- package/src/environment-handlers/node.js +6 -6
- package/src/frontend-model-controller.js +81 -82
- package/src/frontend-model-resource/base-resource.js +78 -115
- package/src/frontend-models/base.js +162 -149
- package/src/frontend-models/clear-pending-debounced-callback.js +1 -1
- package/src/frontend-models/event-hook-models.js +2 -2
- package/src/frontend-models/outgoing-event-buffer.js +2 -2
- package/src/frontend-models/preloader.js +5 -5
- package/src/frontend-models/query.js +43 -38
- package/src/frontend-models/resource-definition.js +6 -6
- package/src/frontend-models/transport-serialization.js +11 -11
- package/src/frontend-models/use-destroyed-event.js +10 -10
- package/src/frontend-models/use-model-class-event.js +11 -11
- package/src/frontend-models/use-updated-event.js +11 -11
- package/src/frontend-models/websocket-channel.js +26 -17
- package/src/frontend-models/websocket-publishers.js +9 -9
- package/src/http-client/response.js +2 -2
- package/src/http-server/client/index.js +8 -8
- package/src/http-server/client/params-to-object.js +10 -10
- package/src/http-server/client/request-buffer/form-data-part.js +2 -2
- package/src/http-server/client/request-buffer/index.js +8 -8
- package/src/http-server/client/request-parser.js +3 -3
- package/src/http-server/client/request-runner.js +6 -6
- package/src/http-server/client/request-timing.js +5 -5
- package/src/http-server/client/request.js +1 -1
- package/src/http-server/client/response.js +5 -5
- package/src/http-server/client/websocket-request.js +4 -4
- package/src/http-server/client/websocket-session.js +18 -18
- package/src/http-server/development-reloader.js +5 -5
- package/src/http-server/index.js +12 -12
- package/src/http-server/remote-address.js +4 -4
- package/src/http-server/server-client.js +3 -3
- package/src/http-server/server-lock.js +4 -4
- package/src/http-server/websocket-channel-subscribers.js +3 -3
- package/src/http-server/websocket-channel.js +1 -1
- package/src/http-server/websocket-connection.js +1 -1
- package/src/http-server/websocket-event-log-store.js +6 -6
- package/src/http-server/websocket-events-host.js +2 -2
- package/src/http-server/worker-handler/in-process.js +7 -7
- package/src/http-server/worker-handler/index.js +4 -4
- package/src/http-server/worker-handler/worker-thread.js +3 -3
- package/src/logger/outputs/array-output.js +3 -3
- package/src/logger/outputs/console-output.js +1 -1
- package/src/logger/outputs/file-output.js +4 -4
- package/src/logger/outputs/stdout-output.js +1 -1
- package/src/logger.js +10 -10
- package/src/mailer/backends/smtp.js +3 -3
- package/src/mailer/base.js +8 -8
- package/src/mailer/delivery.js +4 -4
- package/src/plugins/sqljs-wasm-route-controller.js +1 -1
- package/src/routes/base-route.js +6 -6
- package/src/routes/basic-route.js +1 -1
- package/src/routes/hooks/frontend-model-command-route-hook.js +1 -1
- package/src/routes/index.js +1 -1
- package/src/routes/plugin-routes.js +1 -1
- package/src/routes/resolver.js +11 -11
- package/src/routes/resource-route.js +1 -1
- package/src/testing/browser-frontend-model-event-hook-scenarios.js +7 -7
- package/src/testing/expect-utils.js +11 -11
- package/src/testing/expect.js +7 -7
- package/src/testing/test-files-finder.js +8 -8
- package/src/testing/test-filter-parser.js +2 -2
- package/src/testing/test-runner.js +16 -16
- package/src/testing/test-suite-splitter.js +1 -1
- package/src/testing/test.js +15 -15
- package/src/utils/backtrace-cleaner.js +1 -1
- package/src/utils/format-value.js +1 -1
- package/src/utils/model-scope.js +1 -1
- package/src/utils/ransack.js +26 -26
- package/src/utils/with-tracked-stack-async-hooks.js +7 -7
- package/src/utils/with-tracked-stack.js +3 -3
|
@@ -11,18 +11,26 @@ import {frontendModelResourceClassFromDefinition, frontendModelResourceConfigura
|
|
|
11
11
|
* @property {string} [columnType] - Column type.
|
|
12
12
|
* @property {string} [sqlType] - SQL type.
|
|
13
13
|
* @property {string} [dataType] - Data type.
|
|
14
|
+
* @property {string} [jsDocType] - Exact JSDoc type.
|
|
14
15
|
* @property {string} [name] - Attribute name when configured as an array entry.
|
|
15
16
|
* @property {boolean} [null] - Whether null is allowed.
|
|
17
|
+
* @property {boolean} [selectedByDefault] - Whether the attribute is selected by default.
|
|
16
18
|
* @property {() => string} [getType] - Returns column type.
|
|
17
19
|
* @property {() => boolean} [getNull] - Returns whether null is allowed.
|
|
18
20
|
*/
|
|
19
21
|
/**
|
|
20
22
|
* Permit spec returned by frontend-model resources during generation.
|
|
21
|
-
* @typedef {Array<string | Record<string,
|
|
23
|
+
* @typedef {Array<string | Record<string, FrontendModelGeneratorPermitSpec>>} FrontendModelGeneratorPermitSpec
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
26
|
/** Node CLI command that generates frontend model classes from backend project resource config. */
|
|
25
27
|
export default class DbGenerateFrontendModels extends BaseCommand {
|
|
28
|
+
/** @type {Map<string, string> | null} */
|
|
29
|
+
_resourceMethodReturnTypes = null
|
|
30
|
+
|
|
31
|
+
/** @type {Map<string, string[]> | null} */
|
|
32
|
+
_resourceMethodParameterTypes = null
|
|
33
|
+
|
|
26
34
|
/**
|
|
27
35
|
* Runs execute.
|
|
28
36
|
* @returns {Promise<void>} - Resolves when files are generated.
|
|
@@ -45,15 +53,15 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
45
53
|
|
|
46
54
|
/**
|
|
47
55
|
* Ensured directories.
|
|
48
|
-
|
|
56
|
+
* @type {Set<string>} */
|
|
49
57
|
const ensuredDirectories = new Set()
|
|
50
58
|
/**
|
|
51
59
|
* Generated model names by directory.
|
|
52
|
-
|
|
60
|
+
* @type {Map<string, Set<string>>} */
|
|
53
61
|
const generatedModelNamesByDirectory = new Map()
|
|
54
62
|
/**
|
|
55
63
|
* Generated files by directory.
|
|
56
|
-
|
|
64
|
+
* @type {Map<string, Array<{className: string, fileName: string}>>} */
|
|
57
65
|
const generatedFilesByDirectory = new Map()
|
|
58
66
|
|
|
59
67
|
for (const backendProject of backendProjects) {
|
|
@@ -97,7 +105,9 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
97
105
|
throw new Error(`Invalid frontend model resource definition for '${className}'`)
|
|
98
106
|
}
|
|
99
107
|
|
|
100
|
-
|
|
108
|
+
const resourceClass = frontendModelResourceClassFromDefinition(resources[modelClassName])
|
|
109
|
+
|
|
110
|
+
this.validateModelConfig({availableFrontendModelClassNames, className, modelConfig, resourceClass})
|
|
101
111
|
|
|
102
112
|
if (generatedModelNames.has(className)) {
|
|
103
113
|
throw new Error(`Duplicate frontend model definition for '${className}'`)
|
|
@@ -105,12 +115,12 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
105
115
|
|
|
106
116
|
generatedModelNames.add(className)
|
|
107
117
|
|
|
108
|
-
const fileContent = this.buildModelFileContent({
|
|
118
|
+
const fileContent = await this.buildModelFileContent({
|
|
109
119
|
className,
|
|
110
120
|
importPath,
|
|
111
|
-
modelClass: configuration.getModelClasses()[className],
|
|
121
|
+
modelClass: resourceClass?.ModelClass || configuration.getModelClasses()[className],
|
|
112
122
|
modelConfig,
|
|
113
|
-
resourceClass
|
|
123
|
+
resourceClass
|
|
114
124
|
})
|
|
115
125
|
|
|
116
126
|
await fs.writeFile(filePath, fileContent)
|
|
@@ -192,7 +202,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
192
202
|
availableFrontendModelClassNames(resources) {
|
|
193
203
|
/**
|
|
194
204
|
* Class names.
|
|
195
|
-
|
|
205
|
+
* @type {Set<string>} */
|
|
196
206
|
const classNames = new Set()
|
|
197
207
|
|
|
198
208
|
for (const resourceModelName in resources) {
|
|
@@ -236,10 +246,10 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
236
246
|
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
237
247
|
* @param {import("../../../../../configuration-types.js").NormalizedFrontendModelResourceConfiguration} args.modelConfig - Model configuration.
|
|
238
248
|
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} [args.resourceClass] - Resource class.
|
|
239
|
-
* @returns {string} - Generated file content.
|
|
249
|
+
* @returns {Promise<string>} - Generated file content.
|
|
240
250
|
*/
|
|
241
|
-
buildModelFileContent({className, importPath, modelClass, modelConfig, resourceClass}) {
|
|
242
|
-
const attributes = this.attributeDefinitionsForModel({modelClass, modelConfig})
|
|
251
|
+
async buildModelFileContent({className, importPath, modelClass, modelConfig, resourceClass}) {
|
|
252
|
+
const attributes = await this.attributeDefinitionsForModel({className, modelClass, modelConfig, resourceClass})
|
|
243
253
|
const relationships = this.relationshipsForModel({className, modelConfig, resourceClass})
|
|
244
254
|
const attachments = modelConfig.attachments && typeof modelConfig.attachments === "object"
|
|
245
255
|
? modelConfig.attachments
|
|
@@ -311,8 +321,8 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
311
321
|
}
|
|
312
322
|
fileContent += " */\n"
|
|
313
323
|
}
|
|
314
|
-
fileContent += this.writeAttributesTypedef({attributes, attributesTypeName, nestedWriteTypes, permittedParams: permittedCreateParams, typeName: createAttributesTypeName})
|
|
315
|
-
fileContent += this.writeAttributesTypedef({attributes, attributesTypeName, nestedWriteTypes, permittedParams: permittedUpdateParams, typeName: updateAttributesTypeName})
|
|
324
|
+
fileContent += await this.writeAttributesTypedef({attributes, attributesTypeName, modelClass, nestedWriteTypes, permittedParams: permittedCreateParams, resourceClass, typeName: createAttributesTypeName})
|
|
325
|
+
fileContent += await this.writeAttributesTypedef({attributes, attributesTypeName, modelClass, nestedWriteTypes, permittedParams: permittedUpdateParams, resourceClass, typeName: updateAttributesTypeName})
|
|
316
326
|
fileContent += "/**\n"
|
|
317
327
|
fileContent += ` * Frontend model for ${className}.\n`
|
|
318
328
|
fileContent += ` * @augments {FrontendModelBase<${attributesTypeName}, ${createAttributesTypeName}, ${updateAttributesTypeName}>}\n`
|
|
@@ -418,17 +428,24 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
418
428
|
for (const attribute of attributes) {
|
|
419
429
|
const camelizedAttribute = inflection.camelize(attribute.name, true)
|
|
420
430
|
const camelizedAttributeUpper = inflection.camelize(attribute.name)
|
|
431
|
+
const attributeType = `${attributesTypeName}[${JSON.stringify(attribute.name)}]`
|
|
432
|
+
const setterAttributeType = await this.frontendWriteAttributeType({
|
|
433
|
+
attribute,
|
|
434
|
+
attributeName: attribute.name,
|
|
435
|
+
attributesTypeName,
|
|
436
|
+
resourceClass
|
|
437
|
+
})
|
|
421
438
|
|
|
422
439
|
fileContent += "\n"
|
|
423
|
-
fileContent += ` /** @returns {${
|
|
424
|
-
fileContent += ` ${camelizedAttribute}() { return /** @type {${
|
|
440
|
+
fileContent += ` /** @returns {${attributeType}} - Attribute value. */\n`
|
|
441
|
+
fileContent += ` ${camelizedAttribute}() { return /** @type {${attributeType}} */ (this.readAttribute(${JSON.stringify(attribute.name)})) }\n`
|
|
425
442
|
|
|
426
443
|
fileContent += "\n"
|
|
427
444
|
fileContent += " /**\n"
|
|
428
|
-
fileContent += ` * @param {${
|
|
429
|
-
fileContent += ` * @returns {${
|
|
445
|
+
fileContent += ` * @param {${setterAttributeType}} newValue - New attribute value.\n`
|
|
446
|
+
fileContent += ` * @returns {${setterAttributeType}} - Assigned value.\n`
|
|
430
447
|
fileContent += " */\n"
|
|
431
|
-
fileContent += ` set${camelizedAttributeUpper}(newValue) { return /** @type {${
|
|
448
|
+
fileContent += ` set${camelizedAttributeUpper}(newValue) { return /** @type {${setterAttributeType}} */ (this.setAttribute(${JSON.stringify(attribute.name)}, newValue)) }\n`
|
|
432
449
|
}
|
|
433
450
|
|
|
434
451
|
for (const methodName of Object.keys(collectionCommands)) {
|
|
@@ -553,7 +570,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
553
570
|
fileContent += "\n"
|
|
554
571
|
fileContent += `export {${className}}\n`
|
|
555
572
|
fileContent += "\n"
|
|
556
|
-
fileContent += `export default
|
|
573
|
+
fileContent += `export default ${className}\n`
|
|
557
574
|
|
|
558
575
|
return fileContent
|
|
559
576
|
}
|
|
@@ -595,41 +612,135 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
595
612
|
* @param {object} args - Arguments.
|
|
596
613
|
* @param {Array<{jsDocType: string, name: string}>} args.attributes - Generated read attributes.
|
|
597
614
|
* @param {string} args.attributesTypeName - Generated read attributes typedef name.
|
|
615
|
+
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
598
616
|
* @param {Array<{attributes: Array<{name: string, type: string}>, relationshipName: string, typeName: string}>} args.nestedWriteTypes - Nested write typedefs.
|
|
599
|
-
* @param {
|
|
617
|
+
* @param {FrontendModelGeneratorPermitSpec} args.permittedParams - Resource permitted params spec.
|
|
618
|
+
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined} args.resourceClass - Resource class.
|
|
600
619
|
* @param {string} args.typeName - Typedef name.
|
|
601
|
-
* @returns {string} - Generated typedef source.
|
|
620
|
+
* @returns {Promise<string>} - Generated typedef source.
|
|
602
621
|
*/
|
|
603
|
-
writeAttributesTypedef({attributes, attributesTypeName, nestedWriteTypes, permittedParams, typeName}) {
|
|
604
|
-
|
|
622
|
+
async writeAttributesTypedef({attributes, attributesTypeName, modelClass, nestedWriteTypes, permittedParams, resourceClass, typeName}) {
|
|
623
|
+
const attributeLines = []
|
|
605
624
|
|
|
606
|
-
output
|
|
607
|
-
output += ` * @typedef {object} ${typeName}\n`
|
|
625
|
+
let output = "/**\n"
|
|
608
626
|
|
|
609
627
|
const attributesByName = new Map(attributes.map((attribute) => [attribute.name, attribute]))
|
|
610
628
|
const nestedWriteTypesByKey = new Map(nestedWriteTypes.map((nestedWriteType) => [`${nestedWriteType.relationshipName}Attributes`, nestedWriteType]))
|
|
629
|
+
const emittedAttributeNames = new Set()
|
|
611
630
|
|
|
612
631
|
for (const entry of permittedParams) {
|
|
613
632
|
if (typeof entry == "string") {
|
|
614
|
-
const
|
|
615
|
-
|
|
633
|
+
const attributeName = this.frontendWriteAttributeName({attributeName: entry, attributesByName, modelClass})
|
|
634
|
+
|
|
635
|
+
if (emittedAttributeNames.has(attributeName)) continue
|
|
636
|
+
|
|
637
|
+
emittedAttributeNames.add(attributeName)
|
|
638
|
+
|
|
639
|
+
const type = await this.frontendWriteAttributeType({
|
|
640
|
+
attribute: attributesByName.get(attributeName),
|
|
641
|
+
attributeName,
|
|
642
|
+
attributesTypeName,
|
|
643
|
+
resourceClass
|
|
644
|
+
})
|
|
616
645
|
|
|
617
|
-
|
|
646
|
+
attributeLines.push(` * @property {${type}} [${attributeName}] - Permitted ${attributeName} value.\n`)
|
|
618
647
|
} else if (entry && typeof entry == "object" && !Array.isArray(entry)) {
|
|
619
648
|
for (const key of Object.keys(entry)) {
|
|
620
649
|
const nestedWriteType = nestedWriteTypesByKey.get(key)
|
|
621
650
|
const type = nestedWriteType ? `Array<${nestedWriteType.typeName}>` : "Array<object>"
|
|
622
651
|
|
|
623
|
-
|
|
652
|
+
attributeLines.push(` * @property {${type}} [${key}] - Permitted nested ${key} values.\n`)
|
|
624
653
|
}
|
|
625
654
|
}
|
|
626
655
|
}
|
|
627
656
|
|
|
657
|
+
output += ` * Attributes accepted by ${typeName}.\n`
|
|
658
|
+
if (attributeLines.length === 0) {
|
|
659
|
+
output += ` * @typedef {Record<string, never>} ${typeName}\n`
|
|
660
|
+
} else {
|
|
661
|
+
output += ` * @typedef {object} ${typeName}\n`
|
|
662
|
+
output += attributeLines.join("")
|
|
663
|
+
}
|
|
628
664
|
output += " */\n"
|
|
629
665
|
|
|
630
666
|
return output
|
|
631
667
|
}
|
|
632
668
|
|
|
669
|
+
/**
|
|
670
|
+
* Runs frontend write attribute type.
|
|
671
|
+
* @param {{attribute: {jsDocType: string, name: string} | undefined, attributeName: string, attributesTypeName: string, resourceClass: import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined}} args - Arguments.
|
|
672
|
+
* @returns {Promise<string>} - JSDoc type for the permitted write field.
|
|
673
|
+
*/
|
|
674
|
+
async frontendWriteAttributeType({attribute, attributeName, attributesTypeName, resourceClass}) {
|
|
675
|
+
const setterParameterType = await this.frontendWriteAttributeSetterParameterType({attributeName, resourceClass})
|
|
676
|
+
|
|
677
|
+
if (setterParameterType) return `${setterParameterType} | null`
|
|
678
|
+
|
|
679
|
+
if (!attribute) return "FrontendModelAttributeValue"
|
|
680
|
+
|
|
681
|
+
if (attribute.jsDocType.trim() === "null") return "FrontendModelAttributeValue"
|
|
682
|
+
|
|
683
|
+
return `${attributesTypeName}[${JSON.stringify(attribute.name)}] | null`
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Runs frontend write attribute setter parameter type.
|
|
688
|
+
* @param {{attributeName: string, resourceClass: import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined}} args - Arguments.
|
|
689
|
+
* @returns {Promise<string | null>} - Setter value parameter type when it is useful for generation.
|
|
690
|
+
*/
|
|
691
|
+
async frontendWriteAttributeSetterParameterType({attributeName, resourceClass}) {
|
|
692
|
+
if (!resourceClass?.name) return null
|
|
693
|
+
|
|
694
|
+
const methodName = `set${inflection.camelize(attributeName)}Attribute`
|
|
695
|
+
const parameterType = await this.resourceMethodParameterType({
|
|
696
|
+
methodName,
|
|
697
|
+
parameterIndex: 1,
|
|
698
|
+
sourceClassName: resourceClass.name
|
|
699
|
+
})
|
|
700
|
+
|
|
701
|
+
if (!parameterType) return null
|
|
702
|
+
if (this.isBroadGeneratedType(parameterType)) return null
|
|
703
|
+
|
|
704
|
+
return parameterType
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Runs is broad generated type.
|
|
709
|
+
* @param {string} jsDocType - JSDoc type.
|
|
710
|
+
* @returns {boolean} - Whether the type is too broad to improve generated write typing.
|
|
711
|
+
*/
|
|
712
|
+
isBroadGeneratedType(jsDocType) {
|
|
713
|
+
const normalizedType = jsDocType.trim()
|
|
714
|
+
|
|
715
|
+
return normalizedType === "?"
|
|
716
|
+
|| normalizedType === "any"
|
|
717
|
+
|| normalizedType === "object"
|
|
718
|
+
|| normalizedType === "unknown"
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Resolves a permitted write attribute to the generated frontend attribute name.
|
|
723
|
+
* @param {{attributeName: string, attributesByName: Map<string, {jsDocType: string, name: string}>, modelClass: typeof import("../../../../../database/record/index.js").default | undefined}} args - Arguments.
|
|
724
|
+
* @returns {string} - Frontend attribute name used by generated accessors.
|
|
725
|
+
*/
|
|
726
|
+
frontendWriteAttributeName({attributeName, attributesByName, modelClass}) {
|
|
727
|
+
if (attributesByName.has(attributeName)) return attributeName
|
|
728
|
+
|
|
729
|
+
if (modelClass) {
|
|
730
|
+
const resolvedAttributeName = modelClass.resolveAttributeName(attributeName)
|
|
731
|
+
|
|
732
|
+
if (resolvedAttributeName && attributesByName.has(resolvedAttributeName)) return resolvedAttributeName
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const normalizedAttributeName = inflection.camelize(attributeName, true).toLowerCase()
|
|
736
|
+
const matchingAttributeName = Array.from(attributesByName.keys()).find((candidateName) => candidateName.toLowerCase() === normalizedAttributeName)
|
|
737
|
+
|
|
738
|
+
if (matchingAttributeName) return matchingAttributeName
|
|
739
|
+
|
|
740
|
+
// Write-only virtual params are valid permitted params even when they have no read attribute.
|
|
741
|
+
return attributeName
|
|
742
|
+
}
|
|
743
|
+
|
|
633
744
|
/**
|
|
634
745
|
* Runs nested write types for model.
|
|
635
746
|
* @param {object} args - Arguments.
|
|
@@ -684,10 +795,11 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
684
795
|
if (!Array.isArray(nestedSpec)) return []
|
|
685
796
|
|
|
686
797
|
return nestedSpec.filter((entry) => typeof entry == "string").map((attributeName) => {
|
|
687
|
-
const
|
|
798
|
+
const resolvedAttributeName = targetModelClass?.resolveAttributeName(attributeName) || attributeName
|
|
799
|
+
const attributeConfig = this.frontendAttributeConfigForModelAttribute({attributeName: resolvedAttributeName, modelClass: targetModelClass})
|
|
688
800
|
|
|
689
801
|
return {
|
|
690
|
-
name:
|
|
802
|
+
name: resolvedAttributeName,
|
|
691
803
|
type: attributeConfig ? this.jsDocTypeForFrontendAttribute({attributeConfig}) : "FrontendModelAttributeValue"
|
|
692
804
|
}
|
|
693
805
|
})
|
|
@@ -776,7 +888,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
776
888
|
|
|
777
889
|
/**
|
|
778
890
|
* Relationship names.
|
|
779
|
-
|
|
891
|
+
* @type {string[]} */
|
|
780
892
|
const relationshipNames = []
|
|
781
893
|
|
|
782
894
|
for (const entry of spec) {
|
|
@@ -856,64 +968,172 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
856
968
|
/**
|
|
857
969
|
* Runs attribute definitions for model.
|
|
858
970
|
* @param {object} args - Arguments.
|
|
971
|
+
* @param {string} args.className - Frontend model class name.
|
|
859
972
|
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
860
973
|
* @param {import("../../../../../configuration-types.js").NormalizedFrontendModelResourceConfiguration} args.modelConfig - Model configuration.
|
|
861
|
-
* @
|
|
974
|
+
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null} [args.resourceClass] - Resource class.
|
|
975
|
+
* @returns {Promise<Array<{jsDocType: string, name: string}>>} - Attribute definitions.
|
|
862
976
|
*/
|
|
863
|
-
attributeDefinitionsForModel({modelClass, modelConfig}) {
|
|
977
|
+
async attributeDefinitionsForModel({className, modelClass, modelConfig, resourceClass}) {
|
|
864
978
|
let attributes = modelConfig.attributes
|
|
865
979
|
|
|
866
980
|
// Auto-derive attributes from model columns when not explicitly defined
|
|
867
981
|
if ((!attributes || (Array.isArray(attributes) && attributes.length === 0)) && modelClass) {
|
|
868
|
-
|
|
869
|
-
const columns = modelClass.getColumns()
|
|
982
|
+
const columns = modelClass.getColumns()
|
|
870
983
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
}
|
|
874
|
-
} catch {
|
|
875
|
-
// Model may not be initialized yet
|
|
984
|
+
if (Array.isArray(columns)) {
|
|
985
|
+
attributes = columns.map((column) => inflection.camelize(column.getName(), true))
|
|
876
986
|
}
|
|
877
987
|
}
|
|
878
988
|
|
|
879
989
|
if (Array.isArray(attributes)) {
|
|
880
|
-
|
|
990
|
+
const attributeDefinitions = []
|
|
991
|
+
|
|
992
|
+
for (const attributeDefinition of attributes) {
|
|
881
993
|
/** @type {FrontendAttributeConfig | null} */
|
|
882
|
-
let
|
|
994
|
+
let configuredAttributeConfig = null
|
|
883
995
|
let attributeName
|
|
884
996
|
|
|
885
997
|
if (typeof attributeDefinition == "string") {
|
|
886
998
|
attributeName = attributeDefinition
|
|
887
|
-
attributeConfig = this.frontendAttributeConfigForModelAttribute({attributeName, modelClass})
|
|
888
999
|
} else if (attributeDefinition && typeof attributeDefinition == "object" && !Array.isArray(attributeDefinition)) {
|
|
889
|
-
|
|
890
|
-
attributeName =
|
|
1000
|
+
configuredAttributeConfig = /** @type {FrontendAttributeConfig} */ (attributeDefinition)
|
|
1001
|
+
attributeName = configuredAttributeConfig.name
|
|
891
1002
|
}
|
|
892
1003
|
|
|
893
1004
|
if (typeof attributeName != "string" || attributeName.length < 1) {
|
|
894
1005
|
throw new Error(`Expected frontend model attribute array entries to be strings or objects with a name, got: ${JSON.stringify(attributeDefinition)}`)
|
|
895
1006
|
}
|
|
896
1007
|
|
|
897
|
-
|
|
898
|
-
|
|
1008
|
+
const attributeConfig = await this.resolvedFrontendAttributeConfig({
|
|
1009
|
+
attributeName,
|
|
1010
|
+
className,
|
|
1011
|
+
configuredAttributeConfig,
|
|
1012
|
+
modelClass,
|
|
1013
|
+
resourceClass
|
|
1014
|
+
})
|
|
1015
|
+
|
|
1016
|
+
const frontendAttributeConfig = this.frontendAttributeConfigForGeneratedAttribute({
|
|
1017
|
+
attributeConfig,
|
|
1018
|
+
attributeName,
|
|
1019
|
+
modelClass
|
|
1020
|
+
})
|
|
1021
|
+
|
|
1022
|
+
attributeDefinitions.push({
|
|
1023
|
+
jsDocType: this.jsDocTypeForFrontendAttribute({attributeConfig: frontendAttributeConfig}),
|
|
899
1024
|
name: attributeName
|
|
900
|
-
}
|
|
901
|
-
}
|
|
1025
|
+
})
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
return attributeDefinitions
|
|
902
1029
|
}
|
|
903
1030
|
|
|
904
1031
|
if (!attributes || typeof attributes !== "object") {
|
|
905
1032
|
throw new Error(`Expected 'attributes' as array or object but got: ${attributes}`)
|
|
906
1033
|
}
|
|
907
1034
|
|
|
908
|
-
|
|
1035
|
+
const attributeDefinitions = []
|
|
1036
|
+
|
|
1037
|
+
for (const attributeName of Object.keys(attributes)) {
|
|
909
1038
|
const attributeConfig = attributes[attributeName]
|
|
910
|
-
const
|
|
1039
|
+
const configuredAttributeConfig = attributeConfig && typeof attributeConfig === "object"
|
|
1040
|
+
? /** @type {FrontendAttributeConfig} */ (attributeConfig)
|
|
1041
|
+
: null
|
|
1042
|
+
const normalizedAttributeConfig = await this.resolvedFrontendAttributeConfig({
|
|
1043
|
+
attributeName,
|
|
1044
|
+
className,
|
|
1045
|
+
configuredAttributeConfig,
|
|
1046
|
+
modelClass,
|
|
1047
|
+
resourceClass
|
|
1048
|
+
})
|
|
1049
|
+
const frontendAttributeConfig = this.frontendAttributeConfigForGeneratedAttribute({
|
|
1050
|
+
attributeConfig: normalizedAttributeConfig,
|
|
1051
|
+
attributeName,
|
|
1052
|
+
modelClass
|
|
1053
|
+
})
|
|
911
1054
|
|
|
912
|
-
|
|
913
|
-
jsDocType: this.jsDocTypeForFrontendAttribute({attributeConfig:
|
|
1055
|
+
attributeDefinitions.push({
|
|
1056
|
+
jsDocType: this.jsDocTypeForFrontendAttribute({attributeConfig: frontendAttributeConfig}),
|
|
914
1057
|
name: attributeName
|
|
915
|
-
}
|
|
916
|
-
}
|
|
1058
|
+
})
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
return attributeDefinitions
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/**
|
|
1065
|
+
* Runs frontend attribute config for generated attribute.
|
|
1066
|
+
* @param {{attributeConfig: FrontendAttributeConfig, attributeName: string, modelClass: typeof import("../../../../../database/record/index.js").default | undefined}} args - Arguments.
|
|
1067
|
+
* @returns {FrontendAttributeConfig} - Attribute config used for generated JSDoc.
|
|
1068
|
+
*/
|
|
1069
|
+
frontendAttributeConfigForGeneratedAttribute({attributeConfig, attributeName, modelClass}) {
|
|
1070
|
+
if (!this.frontendAttributeIsModelPrimaryKey({attributeName, modelClass})) return attributeConfig
|
|
1071
|
+
|
|
1072
|
+
return {...attributeConfig, null: false}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Runs frontend attribute is model primary key.
|
|
1077
|
+
* @param {{attributeName: string, modelClass: typeof import("../../../../../database/record/index.js").default | undefined}} args - Arguments.
|
|
1078
|
+
* @returns {boolean} - Whether the attribute is the model primary key.
|
|
1079
|
+
*/
|
|
1080
|
+
frontendAttributeIsModelPrimaryKey({attributeName, modelClass}) {
|
|
1081
|
+
if (!modelClass) return false
|
|
1082
|
+
|
|
1083
|
+
const primaryKey = modelClass.primaryKey()
|
|
1084
|
+
|
|
1085
|
+
if (typeof primaryKey != "string" || primaryKey.length < 1) return false
|
|
1086
|
+
if (attributeName === primaryKey) return true
|
|
1087
|
+
|
|
1088
|
+
return modelClass.resolveAttributeName(primaryKey) === attributeName
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Resolves frontend attribute config from explicit metadata, resource methods, model columns, translated columns, or model accessor JSDoc.
|
|
1093
|
+
* @param {object} args - Arguments.
|
|
1094
|
+
* @param {string} args.attributeName - Frontend attribute name.
|
|
1095
|
+
* @param {string} args.className - Frontend model class name.
|
|
1096
|
+
* @param {FrontendAttributeConfig | null} args.configuredAttributeConfig - Resource-provided attribute config.
|
|
1097
|
+
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
1098
|
+
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined} args.resourceClass - Resource class.
|
|
1099
|
+
* @returns {Promise<FrontendAttributeConfig>} - Resolved frontend attribute config.
|
|
1100
|
+
*/
|
|
1101
|
+
async resolvedFrontendAttributeConfig({attributeName, className, configuredAttributeConfig, modelClass, resourceClass}) {
|
|
1102
|
+
const inferredResourceConfig = await this.frontendAttributeConfigForResourceAttribute({attributeName, resourceClass})
|
|
1103
|
+
const inferredColumnConfig = inferredResourceConfig
|
|
1104
|
+
? null
|
|
1105
|
+
: this.frontendAttributeConfigForModelAttribute({attributeName, modelClass})
|
|
1106
|
+
const inferredTranslatedConfig = inferredResourceConfig || inferredColumnConfig
|
|
1107
|
+
? null
|
|
1108
|
+
: this.frontendAttributeConfigForTranslatedAttribute({attributeName, modelClass, resourceClass})
|
|
1109
|
+
const inferredModelAccessorConfig = inferredResourceConfig || inferredColumnConfig || inferredTranslatedConfig
|
|
1110
|
+
? null
|
|
1111
|
+
: await this.frontendAttributeConfigForModelAccessor({attributeName, modelClass})
|
|
1112
|
+
const inferredConfig = inferredResourceConfig || inferredColumnConfig || inferredTranslatedConfig || inferredModelAccessorConfig
|
|
1113
|
+
|
|
1114
|
+
if (configuredAttributeConfig && this.frontendAttributeConfigHasType(configuredAttributeConfig)) {
|
|
1115
|
+
return inferredConfig
|
|
1116
|
+
? {...inferredConfig, ...configuredAttributeConfig}
|
|
1117
|
+
: configuredAttributeConfig
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (inferredConfig) {
|
|
1121
|
+
return configuredAttributeConfig
|
|
1122
|
+
? {...inferredConfig, ...configuredAttributeConfig}
|
|
1123
|
+
: inferredConfig
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
throw new Error(`Could not infer JSDoc type for frontend model attribute '${className}#${attributeName}'. Add a backend model column, translation table column, explicit resource metadata, or a @returns JSDoc type on ${resourceClass?.name || "the resource"}.${attributeName}Attribute().`)
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
* Runs frontend attribute config has type.
|
|
1131
|
+
* @param {FrontendAttributeConfig | null | undefined} attributeConfig - Attribute config.
|
|
1132
|
+
* @returns {boolean} - Whether the config declares a type source.
|
|
1133
|
+
*/
|
|
1134
|
+
frontendAttributeConfigHasType(attributeConfig) {
|
|
1135
|
+
return typeof this.frontendAttributeTypeValue(attributeConfig) == "string"
|
|
1136
|
+
|| typeof attributeConfig?.jsDocType == "string"
|
|
917
1137
|
}
|
|
918
1138
|
|
|
919
1139
|
/**
|
|
@@ -923,6 +1143,10 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
923
1143
|
* @returns {string} - JSDoc type.
|
|
924
1144
|
*/
|
|
925
1145
|
jsDocTypeForFrontendAttribute({attributeConfig}) {
|
|
1146
|
+
if (attributeConfig && typeof attributeConfig.jsDocType == "string" && attributeConfig.jsDocType.length > 0) {
|
|
1147
|
+
return attributeConfig.jsDocType
|
|
1148
|
+
}
|
|
1149
|
+
|
|
926
1150
|
const jsDocType = this.jsDocTypeForFrontendAttributeBaseType(attributeConfig)
|
|
927
1151
|
|
|
928
1152
|
if (!this.frontendAttributeCanBeNull(attributeConfig)) {
|
|
@@ -948,7 +1172,7 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
948
1172
|
return "boolean"
|
|
949
1173
|
} else if (type == "json" || type == "jsonb") {
|
|
950
1174
|
return "FrontendModelTransportValue"
|
|
951
|
-
} else if (type && ["blob", "char", "nvarchar", "varchar", "text", "longtext", "uuid", "character varying"].includes(type)) {
|
|
1175
|
+
} else if (type && ["blob", "char", "nvarchar", "varchar", "text", "longtext", "mediumtext", "tinytext", "uuid", "character varying"].includes(type)) {
|
|
952
1176
|
return "string"
|
|
953
1177
|
} else if (type && ["bit", "bigint", "decimal", "double", "double precision", "float", "int", "integer", "numeric", "real", "smallint", "tinyint"].includes(type)) {
|
|
954
1178
|
return "number"
|
|
@@ -999,6 +1223,517 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
999
1223
|
return typeValue
|
|
1000
1224
|
}
|
|
1001
1225
|
|
|
1226
|
+
/**
|
|
1227
|
+
* Runs frontend attribute config for resource attribute.
|
|
1228
|
+
* @param {object} args - Arguments.
|
|
1229
|
+
* @param {string} args.attributeName - Frontend model attribute name.
|
|
1230
|
+
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined} args.resourceClass - Resource class.
|
|
1231
|
+
* @returns {Promise<FrontendAttributeConfig | null>} - Attribute config inferred from resource method JSDoc.
|
|
1232
|
+
*/
|
|
1233
|
+
async frontendAttributeConfigForResourceAttribute({attributeName, resourceClass}) {
|
|
1234
|
+
if (!resourceClass) return null
|
|
1235
|
+
|
|
1236
|
+
const methodName = `${attributeName}Attribute`
|
|
1237
|
+
const ownerClassName = this.methodOwnerClassName({methodName, targetClass: resourceClass})
|
|
1238
|
+
|
|
1239
|
+
if (!ownerClassName) return null
|
|
1240
|
+
|
|
1241
|
+
const jsDocType = await this.resourceMethodReturnType({
|
|
1242
|
+
methodName,
|
|
1243
|
+
sourceClassName: ownerClassName
|
|
1244
|
+
})
|
|
1245
|
+
|
|
1246
|
+
return jsDocType ? {jsDocType: this.unwrappedPromiseJsDocType({jsDocType})} : null
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
/**
|
|
1250
|
+
* Runs frontend attribute config for translated attribute.
|
|
1251
|
+
* @param {object} args - Arguments.
|
|
1252
|
+
* @param {string} args.attributeName - Frontend model attribute name.
|
|
1253
|
+
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
1254
|
+
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined} args.resourceClass - Resource class.
|
|
1255
|
+
* @returns {FrontendAttributeConfig | null} - Attribute config inferred from translated attribute columns.
|
|
1256
|
+
*/
|
|
1257
|
+
frontendAttributeConfigForTranslatedAttribute({attributeName, modelClass, resourceClass}) {
|
|
1258
|
+
if (!modelClass) return null
|
|
1259
|
+
if (!this.frontendAttributeIsTranslated({attributeName, modelClass, resourceClass})) return null
|
|
1260
|
+
|
|
1261
|
+
const TranslationClass = modelClass.getTranslationClass()
|
|
1262
|
+
const columnName = inflection.underscore(attributeName)
|
|
1263
|
+
|
|
1264
|
+
let column
|
|
1265
|
+
|
|
1266
|
+
try {
|
|
1267
|
+
column = TranslationClass.getColumnsHash()[columnName]
|
|
1268
|
+
} catch (error) {
|
|
1269
|
+
if (error instanceof Error && (error.message.includes("hasn't been initialized yet") || error.message.includes("used before initialization"))) return null
|
|
1270
|
+
|
|
1271
|
+
throw error
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
return column ? this.frontendAttributeConfigForColumn({column}) : null
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
/**
|
|
1278
|
+
* Runs frontend attribute is translated.
|
|
1279
|
+
* @param {object} args - Arguments.
|
|
1280
|
+
* @param {string} args.attributeName - Frontend model attribute name.
|
|
1281
|
+
* @param {typeof import("../../../../../database/record/index.js").default} args.modelClass - Backend model class.
|
|
1282
|
+
* @param {import("../../../../../configuration-types.js").FrontendModelResourceClassType | null | undefined} args.resourceClass - Resource class.
|
|
1283
|
+
* @returns {boolean} - Whether the frontend attribute is translated.
|
|
1284
|
+
*/
|
|
1285
|
+
frontendAttributeIsTranslated({attributeName, modelClass, resourceClass}) {
|
|
1286
|
+
if (resourceClass) {
|
|
1287
|
+
const translatedAttributes = resourceClass.translatedAttributes
|
|
1288
|
+
|
|
1289
|
+
if (Array.isArray(translatedAttributes) && translatedAttributes.includes(attributeName)) return true
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
const translations = modelClass._translations
|
|
1293
|
+
|
|
1294
|
+
return Boolean(translations && typeof translations == "object" && Object.prototype.hasOwnProperty.call(translations, attributeName))
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
/**
|
|
1298
|
+
* Runs frontend attribute config for model accessor.
|
|
1299
|
+
* @param {object} args - Arguments.
|
|
1300
|
+
* @param {string} args.attributeName - Frontend model attribute name.
|
|
1301
|
+
* @param {typeof import("../../../../../database/record/index.js").default | undefined} args.modelClass - Backend model class.
|
|
1302
|
+
* @returns {Promise<FrontendAttributeConfig | null>} - Attribute config inferred from model accessor JSDoc.
|
|
1303
|
+
*/
|
|
1304
|
+
async frontendAttributeConfigForModelAccessor({attributeName, modelClass}) {
|
|
1305
|
+
if (!modelClass) return null
|
|
1306
|
+
|
|
1307
|
+
const ownerClassName = this.methodOwnerClassName({methodName: attributeName, targetClass: modelClass})
|
|
1308
|
+
|
|
1309
|
+
if (!ownerClassName) return null
|
|
1310
|
+
|
|
1311
|
+
const jsDocType = await this.resourceMethodReturnType({
|
|
1312
|
+
methodName: attributeName,
|
|
1313
|
+
sourceClassName: ownerClassName
|
|
1314
|
+
})
|
|
1315
|
+
|
|
1316
|
+
return jsDocType ? {jsDocType} : null
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/**
|
|
1320
|
+
* Runs unwrapped promise js doc type.
|
|
1321
|
+
* @param {object} args - Arguments.
|
|
1322
|
+
* @param {string} args.jsDocType - JSDoc type to normalize.
|
|
1323
|
+
* @returns {string} - The resolved value type for serialized frontend attributes.
|
|
1324
|
+
*/
|
|
1325
|
+
unwrappedPromiseJsDocType({jsDocType}) {
|
|
1326
|
+
const promisePrefix = "Promise<"
|
|
1327
|
+
|
|
1328
|
+
if (!jsDocType.startsWith(promisePrefix)) return jsDocType
|
|
1329
|
+
|
|
1330
|
+
if (!jsDocType.endsWith(">")) {
|
|
1331
|
+
throw new Error(`Expected Promise JSDoc type to end with '>': ${jsDocType}`)
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
const resolvedType = jsDocType.slice(promisePrefix.length, -1).trim()
|
|
1335
|
+
|
|
1336
|
+
if (resolvedType.length < 1) {
|
|
1337
|
+
throw new Error(`Expected Promise JSDoc type to contain a resolved type: ${jsDocType}`)
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
return resolvedType
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
/**
|
|
1344
|
+
* Runs method owner class name.
|
|
1345
|
+
* @param {object} args - Arguments.
|
|
1346
|
+
* @param {string} args.methodName - Method name.
|
|
1347
|
+
* @param {typeof import("../../../../../database/record/index.js").default | import("../../../../../configuration-types.js").FrontendModelResourceClassType} args.targetClass - Target class.
|
|
1348
|
+
* @returns {string | null} - Class name that declares the method.
|
|
1349
|
+
*/
|
|
1350
|
+
methodOwnerClassName({methodName, targetClass}) {
|
|
1351
|
+
let prototype = targetClass.prototype
|
|
1352
|
+
|
|
1353
|
+
while (prototype && prototype !== Object.prototype) {
|
|
1354
|
+
if (Object.prototype.hasOwnProperty.call(prototype, methodName)) {
|
|
1355
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, methodName)
|
|
1356
|
+
|
|
1357
|
+
if (typeof descriptor?.value != "function") return null
|
|
1358
|
+
|
|
1359
|
+
const constructorName = prototype.constructor?.name
|
|
1360
|
+
|
|
1361
|
+
if (typeof constructorName == "string" && constructorName.length > 0) return constructorName
|
|
1362
|
+
|
|
1363
|
+
return null
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
prototype = Object.getPrototypeOf(prototype)
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
return null
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
/**
|
|
1373
|
+
* Runs resource method return type.
|
|
1374
|
+
* @param {object} args - Arguments.
|
|
1375
|
+
* @param {string} args.methodName - Method name.
|
|
1376
|
+
* @param {string} args.sourceClassName - Source class name.
|
|
1377
|
+
* @returns {Promise<string | null>} - JSDoc return type when documented.
|
|
1378
|
+
*/
|
|
1379
|
+
async resourceMethodReturnType({methodName, sourceClassName}) {
|
|
1380
|
+
const resourceMethodReturnTypes = await this.resourceMethodReturnTypes()
|
|
1381
|
+
const returnTypeKey = `${sourceClassName}.${methodName}`
|
|
1382
|
+
|
|
1383
|
+
if (!resourceMethodReturnTypes.has(returnTypeKey)) return null
|
|
1384
|
+
|
|
1385
|
+
const returnType = resourceMethodReturnTypes.get(returnTypeKey)
|
|
1386
|
+
|
|
1387
|
+
if (typeof returnType != "string" || returnType.length < 1) {
|
|
1388
|
+
throw new Error(`Expected non-empty JSDoc return type for ${returnTypeKey}`)
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
return returnType
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* Runs resource method parameter type.
|
|
1396
|
+
* @param {{methodName: string, parameterIndex: number, sourceClassName: string}} args - Arguments.
|
|
1397
|
+
* @returns {Promise<string | null>} - JSDoc parameter type when documented.
|
|
1398
|
+
*/
|
|
1399
|
+
async resourceMethodParameterType({methodName, parameterIndex, sourceClassName}) {
|
|
1400
|
+
const resourceMethodParameterTypes = await this.resourceMethodParameterTypes()
|
|
1401
|
+
const parameterTypesKey = `${sourceClassName}.${methodName}`
|
|
1402
|
+
|
|
1403
|
+
if (!resourceMethodParameterTypes.has(parameterTypesKey)) return null
|
|
1404
|
+
|
|
1405
|
+
const parameterTypes = resourceMethodParameterTypes.get(parameterTypesKey)
|
|
1406
|
+
|
|
1407
|
+
if (!parameterTypes) {
|
|
1408
|
+
throw new Error(`Expected JSDoc parameter types for ${parameterTypesKey}`)
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
const parameterType = parameterTypes[parameterIndex]
|
|
1412
|
+
|
|
1413
|
+
if (parameterType === undefined) return null
|
|
1414
|
+
|
|
1415
|
+
if (parameterType.length < 1) {
|
|
1416
|
+
throw new Error(`Expected non-empty JSDoc parameter type for ${parameterTypesKey} parameter ${parameterIndex}`)
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
return parameterType
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Runs resource method return types.
|
|
1424
|
+
* @returns {Promise<Map<string, string>>} - Resource method return types keyed by ClassName.methodName.
|
|
1425
|
+
*/
|
|
1426
|
+
async resourceMethodReturnTypes() {
|
|
1427
|
+
if (this._resourceMethodReturnTypes) return this._resourceMethodReturnTypes
|
|
1428
|
+
|
|
1429
|
+
const sourceFiles = await this.frontendModelJsDocSourceFiles()
|
|
1430
|
+
const returnTypes = new Map()
|
|
1431
|
+
|
|
1432
|
+
for (const sourceFile of sourceFiles) {
|
|
1433
|
+
const sourceText = await fs.readFile(sourceFile, "utf8")
|
|
1434
|
+
|
|
1435
|
+
this.addResourceMethodReturnTypesFromSource({returnTypes, sourceText})
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
this._resourceMethodReturnTypes = returnTypes
|
|
1439
|
+
|
|
1440
|
+
return returnTypes
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
/**
|
|
1444
|
+
* Runs resource method parameter types.
|
|
1445
|
+
* @returns {Promise<Map<string, string[]>>} - Resource method parameter types keyed by ClassName.methodName.
|
|
1446
|
+
*/
|
|
1447
|
+
async resourceMethodParameterTypes() {
|
|
1448
|
+
if (this._resourceMethodParameterTypes) return this._resourceMethodParameterTypes
|
|
1449
|
+
|
|
1450
|
+
const sourceFiles = await this.frontendModelJsDocSourceFiles()
|
|
1451
|
+
const parameterTypes = new Map()
|
|
1452
|
+
|
|
1453
|
+
for (const sourceFile of sourceFiles) {
|
|
1454
|
+
const sourceText = await fs.readFile(sourceFile, "utf8")
|
|
1455
|
+
|
|
1456
|
+
this.addResourceMethodParameterTypesFromSource({parameterTypes, sourceText})
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
this._resourceMethodParameterTypes = parameterTypes
|
|
1460
|
+
|
|
1461
|
+
return parameterTypes
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
/**
|
|
1465
|
+
* Runs frontend model JSDoc source files.
|
|
1466
|
+
* @returns {Promise<string[]>} - JavaScript source files that can define frontend-model resources and model accessors.
|
|
1467
|
+
*/
|
|
1468
|
+
async frontendModelJsDocSourceFiles() {
|
|
1469
|
+
const sourceFiles = []
|
|
1470
|
+
|
|
1471
|
+
for (const sourceDirectory of this.frontendModelJsDocSourceDirectories()) {
|
|
1472
|
+
sourceFiles.push(...await this.javascriptFilesInDirectory(sourceDirectory))
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
return sourceFiles
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* Runs frontend model JSDoc source directories.
|
|
1480
|
+
* @returns {string[]} - Source directories to scan for generated frontend-model JSDoc.
|
|
1481
|
+
*/
|
|
1482
|
+
frontendModelJsDocSourceDirectories() {
|
|
1483
|
+
const sourceDirectories = new Set([path.join(this.directory(), "src")])
|
|
1484
|
+
|
|
1485
|
+
for (const backendProject of this.getConfiguration().getBackendProjects()) {
|
|
1486
|
+
if (typeof backendProject.path == "string" && backendProject.path.length > 0) {
|
|
1487
|
+
sourceDirectories.add(path.join(backendProject.path, "src"))
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
return Array.from(sourceDirectories)
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
/**
|
|
1495
|
+
* Adds resource method return types from source.
|
|
1496
|
+
* @param {object} args - Arguments.
|
|
1497
|
+
* @param {Map<string, string>} args.returnTypes - Mutable return types map.
|
|
1498
|
+
* @param {string} args.sourceText - Source text.
|
|
1499
|
+
* @returns {void}
|
|
1500
|
+
*/
|
|
1501
|
+
addResourceMethodReturnTypesFromSource({returnTypes, sourceText}) {
|
|
1502
|
+
const classRegex = /class\s+([A-Za-z_$][\w$]*)\s+(?:extends\s+[^{]+)?\{/g
|
|
1503
|
+
let classMatch
|
|
1504
|
+
|
|
1505
|
+
while ((classMatch = classRegex.exec(sourceText))) {
|
|
1506
|
+
const className = classMatch[1]
|
|
1507
|
+
const classBodyStart = classRegex.lastIndex
|
|
1508
|
+
const classBodyEnd = this.matchingBraceIndex({openIndex: classBodyStart - 1, sourceText})
|
|
1509
|
+
|
|
1510
|
+
if (classBodyEnd == null) {
|
|
1511
|
+
throw new Error(`Could not find closing brace for resource class '${className}' while reading frontend attribute JSDoc`)
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
const classBody = sourceText.slice(classBodyStart, classBodyEnd)
|
|
1515
|
+
const jsDocRegex = /\/\*\*([\s\S]*?)\*\//g
|
|
1516
|
+
let jsDocMatch
|
|
1517
|
+
|
|
1518
|
+
while ((jsDocMatch = jsDocRegex.exec(classBody))) {
|
|
1519
|
+
const sourceAfterJsDoc = classBody.slice(jsDocRegex.lastIndex)
|
|
1520
|
+
const methodMatch = sourceAfterJsDoc.match(/^\s*(?:async\s+)?([A-Za-z_$][\w$]*)\s*\(/)
|
|
1521
|
+
|
|
1522
|
+
if (!methodMatch) continue
|
|
1523
|
+
|
|
1524
|
+
const methodName = methodMatch[1]
|
|
1525
|
+
|
|
1526
|
+
const returnType = this.jsDocReturnType(jsDocMatch[1])
|
|
1527
|
+
|
|
1528
|
+
if (returnType) {
|
|
1529
|
+
returnTypes.set(`${className}.${methodName}`, returnType)
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
classRegex.lastIndex = classBodyEnd + 1
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
/**
|
|
1538
|
+
* Adds resource method parameter types from source.
|
|
1539
|
+
* @param {{parameterTypes: Map<string, string[]>, sourceText: string}} args - Arguments.
|
|
1540
|
+
* @returns {void}
|
|
1541
|
+
*/
|
|
1542
|
+
addResourceMethodParameterTypesFromSource({parameterTypes, sourceText}) {
|
|
1543
|
+
const classRegex = /class\s+([A-Za-z_$][\w$]*)\s+(?:extends\s+[^{]+)?\{/g
|
|
1544
|
+
let classMatch
|
|
1545
|
+
|
|
1546
|
+
while ((classMatch = classRegex.exec(sourceText))) {
|
|
1547
|
+
const className = classMatch[1]
|
|
1548
|
+
const classBodyStart = classRegex.lastIndex
|
|
1549
|
+
const classBodyEnd = this.matchingBraceIndex({openIndex: classBodyStart - 1, sourceText})
|
|
1550
|
+
|
|
1551
|
+
if (classBodyEnd == null) {
|
|
1552
|
+
throw new Error(`Could not find closing brace for resource class '${className}' while reading frontend attribute JSDoc`)
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
const classBody = sourceText.slice(classBodyStart, classBodyEnd)
|
|
1556
|
+
const jsDocRegex = /\/\*\*([\s\S]*?)\*\//g
|
|
1557
|
+
let jsDocMatch
|
|
1558
|
+
|
|
1559
|
+
while ((jsDocMatch = jsDocRegex.exec(classBody))) {
|
|
1560
|
+
const sourceAfterJsDoc = classBody.slice(jsDocRegex.lastIndex)
|
|
1561
|
+
const methodMatch = sourceAfterJsDoc.match(/^\s*(?:async\s+)?([A-Za-z_$][\w$]*)\s*\(/)
|
|
1562
|
+
|
|
1563
|
+
if (!methodMatch) continue
|
|
1564
|
+
|
|
1565
|
+
const methodName = methodMatch[1]
|
|
1566
|
+
const jsDocParameterTypes = this.jsDocParameterTypes(jsDocMatch[1])
|
|
1567
|
+
|
|
1568
|
+
if (jsDocParameterTypes.length > 0) {
|
|
1569
|
+
parameterTypes.set(`${className}.${methodName}`, jsDocParameterTypes)
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
classRegex.lastIndex = classBodyEnd + 1
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
/**
|
|
1578
|
+
* Runs js doc return type.
|
|
1579
|
+
* @param {string} jsDocText - JSDoc text inside comment markers.
|
|
1580
|
+
* @returns {string | null} - JSDoc return type when present.
|
|
1581
|
+
*/
|
|
1582
|
+
jsDocReturnType(jsDocText) {
|
|
1583
|
+
const returnsMatch = jsDocText.match(/@returns?\s*\{/)
|
|
1584
|
+
|
|
1585
|
+
if (!returnsMatch || returnsMatch.index == null) return null
|
|
1586
|
+
|
|
1587
|
+
const typeOpenIndex = returnsMatch.index + returnsMatch[0].length - 1
|
|
1588
|
+
const typeCloseIndex = this.matchingBraceIndex({openIndex: typeOpenIndex, sourceText: jsDocText})
|
|
1589
|
+
|
|
1590
|
+
if (typeCloseIndex == null) {
|
|
1591
|
+
throw new Error(`Could not parse JSDoc return type from: ${jsDocText}`)
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
const returnType = jsDocText.slice(typeOpenIndex + 1, typeCloseIndex).trim()
|
|
1595
|
+
|
|
1596
|
+
if (returnType.length < 1) {
|
|
1597
|
+
throw new Error(`Expected non-empty JSDoc return type in: ${jsDocText}`)
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
return returnType
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Runs js doc parameter types.
|
|
1605
|
+
* @param {string} jsDocText - JSDoc text inside comment markers.
|
|
1606
|
+
* @returns {string[]} - JSDoc parameter types in declaration order.
|
|
1607
|
+
*/
|
|
1608
|
+
jsDocParameterTypes(jsDocText) {
|
|
1609
|
+
const parameterTypes = []
|
|
1610
|
+
const paramRegex = /@param\s*\{/g
|
|
1611
|
+
let _paramMatch
|
|
1612
|
+
|
|
1613
|
+
while ((_paramMatch = paramRegex.exec(jsDocText))) {
|
|
1614
|
+
const typeOpenIndex = paramRegex.lastIndex - 1
|
|
1615
|
+
const typeCloseIndex = this.matchingBraceIndex({openIndex: typeOpenIndex, sourceText: jsDocText})
|
|
1616
|
+
|
|
1617
|
+
if (typeCloseIndex == null) {
|
|
1618
|
+
throw new Error(`Could not parse JSDoc parameter type from: ${jsDocText}`)
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
const parameterType = jsDocText.slice(typeOpenIndex + 1, typeCloseIndex).trim()
|
|
1622
|
+
|
|
1623
|
+
if (parameterType.length < 1) {
|
|
1624
|
+
throw new Error(`Expected non-empty JSDoc parameter type in: ${jsDocText}`)
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
parameterTypes.push(parameterType)
|
|
1628
|
+
paramRegex.lastIndex = typeCloseIndex + 1
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
return parameterTypes
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
/**
|
|
1635
|
+
* Runs javascript files in directory.
|
|
1636
|
+
* @param {string} directory - Directory path.
|
|
1637
|
+
* @returns {Promise<string[]>} - JavaScript source file paths.
|
|
1638
|
+
*/
|
|
1639
|
+
async javascriptFilesInDirectory(directory) {
|
|
1640
|
+
let entries
|
|
1641
|
+
|
|
1642
|
+
try {
|
|
1643
|
+
entries = await fs.readdir(directory, {withFileTypes: true})
|
|
1644
|
+
} catch (error) {
|
|
1645
|
+
if (error && typeof error == "object" && "code" in error && error.code === "ENOENT") return []
|
|
1646
|
+
|
|
1647
|
+
throw error
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const filePaths = []
|
|
1651
|
+
|
|
1652
|
+
for (const entry of entries) {
|
|
1653
|
+
const entryPath = path.join(directory, entry.name)
|
|
1654
|
+
|
|
1655
|
+
if (entry.isDirectory()) {
|
|
1656
|
+
filePaths.push(...await this.javascriptFilesInDirectory(entryPath))
|
|
1657
|
+
} else if (entry.isFile() && /\.(mjs|js|jsx|ts)$/.test(entry.name)) {
|
|
1658
|
+
filePaths.push(entryPath)
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
return filePaths
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* Finds a matching closing brace while respecting JavaScript strings and comments.
|
|
1667
|
+
* @param {object} args - Arguments.
|
|
1668
|
+
* @param {number} args.openIndex - Opening brace index.
|
|
1669
|
+
* @param {string} args.sourceText - Source text.
|
|
1670
|
+
* @returns {number | null} - Closing brace index when found.
|
|
1671
|
+
*/
|
|
1672
|
+
matchingBraceIndex({openIndex, sourceText}) {
|
|
1673
|
+
if (sourceText[openIndex] !== "{") {
|
|
1674
|
+
throw new Error(`Expected opening brace at index ${openIndex}`)
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
let depth = 0
|
|
1678
|
+
let inBlockComment = false
|
|
1679
|
+
let inLineComment = false
|
|
1680
|
+
let inString = ""
|
|
1681
|
+
|
|
1682
|
+
for (let index = openIndex; index < sourceText.length; index++) {
|
|
1683
|
+
const char = sourceText[index]
|
|
1684
|
+
const nextChar = sourceText[index + 1]
|
|
1685
|
+
const previousChar = sourceText[index - 1]
|
|
1686
|
+
|
|
1687
|
+
if (inLineComment) {
|
|
1688
|
+
if (char === "\n") inLineComment = false
|
|
1689
|
+
|
|
1690
|
+
continue
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
if (inBlockComment) {
|
|
1694
|
+
if (char === "*" && nextChar === "/") {
|
|
1695
|
+
inBlockComment = false
|
|
1696
|
+
index++
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
continue
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
if (inString) {
|
|
1703
|
+
if (char === inString && previousChar !== "\\") inString = ""
|
|
1704
|
+
|
|
1705
|
+
continue
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
if (char === "/" && nextChar === "/") {
|
|
1709
|
+
inLineComment = true
|
|
1710
|
+
index++
|
|
1711
|
+
continue
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
if (char === "/" && nextChar === "*") {
|
|
1715
|
+
inBlockComment = true
|
|
1716
|
+
index++
|
|
1717
|
+
continue
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
1721
|
+
inString = char
|
|
1722
|
+
continue
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
if (char === "{") {
|
|
1726
|
+
depth++
|
|
1727
|
+
} else if (char === "}") {
|
|
1728
|
+
depth--
|
|
1729
|
+
|
|
1730
|
+
if (depth === 0) return index
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
return null
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1002
1737
|
/**
|
|
1003
1738
|
* Runs frontend attribute config for model attribute.
|
|
1004
1739
|
* @param {object} args - Arguments.
|
|
@@ -1011,13 +1746,54 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
1011
1746
|
return null
|
|
1012
1747
|
}
|
|
1013
1748
|
|
|
1014
|
-
const
|
|
1749
|
+
const resolvedAttributeName = modelClass.resolveAttributeName(attributeName)
|
|
1750
|
+
|
|
1751
|
+
if (!resolvedAttributeName) return null
|
|
1752
|
+
|
|
1753
|
+
let columnName
|
|
1754
|
+
|
|
1755
|
+
try {
|
|
1756
|
+
columnName = modelClass.getAttributeNameToColumnNameMap()[resolvedAttributeName]
|
|
1757
|
+
} catch (error) {
|
|
1758
|
+
if (error instanceof Error && error.message.includes("used before initialization")) return null
|
|
1759
|
+
|
|
1760
|
+
throw error
|
|
1761
|
+
}
|
|
1015
1762
|
|
|
1016
1763
|
if (!columnName) {
|
|
1017
1764
|
return null
|
|
1018
1765
|
}
|
|
1019
1766
|
|
|
1020
|
-
|
|
1767
|
+
let column
|
|
1768
|
+
|
|
1769
|
+
try {
|
|
1770
|
+
column = modelClass.getColumnsHash()[columnName]
|
|
1771
|
+
} catch (error) {
|
|
1772
|
+
if (error instanceof Error && error.message.includes("used before initialization")) return null
|
|
1773
|
+
|
|
1774
|
+
throw error
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
return column ? this.frontendAttributeConfigForColumn({column}) : null
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
/**
|
|
1781
|
+
* Runs frontend attribute config for column.
|
|
1782
|
+
* @param {object} args - Arguments.
|
|
1783
|
+
* @param {import("../../../../../database/drivers/base-column.js").default} args.column - Database column.
|
|
1784
|
+
* @returns {FrontendAttributeConfig} - Attribute config inferred from the database column.
|
|
1785
|
+
*/
|
|
1786
|
+
frontendAttributeConfigForColumn({column}) {
|
|
1787
|
+
const type = column.getType()
|
|
1788
|
+
|
|
1789
|
+
if (typeof type != "string" || type.length < 1) {
|
|
1790
|
+
throw new Error(`Expected non-empty column type for frontend model attribute inference, got: ${type}`)
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
return {
|
|
1794
|
+
null: column.getNull(),
|
|
1795
|
+
type
|
|
1796
|
+
}
|
|
1021
1797
|
}
|
|
1022
1798
|
|
|
1023
1799
|
/**
|