@restforgejs/platform 4.1.1 → 4.3.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/SECURITY.md +83 -4
- package/bin/sdf-tools.exe +0 -0
- package/build-info.json +2 -2
- package/cli/consumer-deploy.js +1 -1
- package/cli/consumer.js +1 -1
- package/generators/cli/dashboard/create.js +4 -1
- package/generators/cli/endpoint/create.js +43 -4
- package/generators/cli/key/generate.js +2 -1
- package/generators/cli/key/revoke.js +2 -1
- package/generators/cli/payload/diff.js +3 -2
- package/generators/cli/payload/generate.js +3 -2
- package/generators/cli/payload/sync.js +3 -2
- package/generators/cli/payload/validate.js +3 -2
- package/generators/cli/processor/create.js +14 -3
- package/generators/cli/project/delete.js +2 -1
- package/generators/cli/query/validate.js +3 -2
- package/generators/cli/schema/apply.js +526 -0
- package/generators/cli/schema/describe.js +3 -2
- package/generators/cli/schema/diff.js +322 -0
- package/generators/cli/schema/generate-ddl.js +7 -10
- package/generators/cli/schema/init.js +95 -172
- package/generators/cli/schema/introspect.js +3 -2
- package/generators/cli/schema/list.js +3 -2
- package/generators/cli/schema/migrate.js +13 -18
- package/generators/cli/schema/models.js +8 -12
- package/generators/cli/schema/template.js +222 -0
- package/generators/cli/schema/validate.js +8 -12
- package/generators/cli-entry.js +17 -2
- package/generators/lib/dbschema-kit/apply-engine.js +582 -0
- package/generators/lib/dbschema-kit/diff-engine.js +703 -0
- package/generators/lib/dbschema-kit/diff-reporter.js +272 -0
- package/generators/lib/dbschema-kit/emitters/alter-table.js +275 -0
- package/generators/lib/migration/audit-table-runner.js +213 -215
- package/generators/lib/payload/endpoint-schema-validator.js +171 -0
- package/generators/lib/payload/payload-runner.js +137 -220
- package/generators/lib/payload/schema-diff.js +277 -0
- package/generators/lib/templates/dashboard-catalog.js +1 -437
- package/generators/lib/templates/db-connection-env.js +1 -212
- package/generators/lib/templates/dbschema-catalog.js +1 -489
- package/generators/lib/templates/field-validation-catalog.js +1 -531
- package/generators/lib/templates/mysql-template.js +1 -3863
- package/generators/lib/templates/oracle-template.js +1 -3915
- package/generators/lib/templates/postgres-template.js +1 -5838
- package/generators/lib/templates/query-declarative-catalog.js +1 -199
- package/generators/lib/templates/sqlite-template.js +1 -3440
- package/generators/lib/utils/audit-columns.js +181 -0
- package/generators/lib/utils/cli-output.js +17 -0
- package/generators/lib/utils/database-introspector.js +16 -13
- package/generators/lib/utils/env-manager.js +6 -0
- package/generators/lib/utils/path-validator.js +71 -0
- package/generators/lib/validators/payload-validator.js +1 -2
- package/integrity-manifest.json +28 -10
- package/package.json +11 -3
- package/scripts/verify-integrity.js +1 -1
- package/server.js +1 -1
- package/src/components/handlers/adjust_handler.js +1 -1
- package/src/components/handlers/audit_handler.js +1 -1
- package/src/components/handlers/delete_handler.js +1 -1
- package/src/components/handlers/export_handler.js +1 -1
- package/src/components/handlers/import_handler.js +1 -1
- package/src/components/handlers/insert_handler.js +1 -1
- package/src/components/handlers/update_handler.js +1 -1
- package/src/components/handlers/upload_handler.js +1 -1
- package/src/components/handlers/workflow_handler.js +1 -1
- package/src/components/integrations/webhook.js +1 -1
- package/src/consumers/baseConsumer.js +1 -1
- package/src/consumers/declarativeMapper.js +1 -1
- package/src/consumers/handlers/apiHandler.js +1 -1
- package/src/consumers/handlers/consoleHandler.js +1 -1
- package/src/consumers/handlers/databaseHandler.js +1 -1
- package/src/consumers/handlers/index.js +1 -1
- package/src/consumers/handlers/kafkaHandler.js +1 -1
- package/src/consumers/index.js +1 -1
- package/src/consumers/messageTransformer.js +1 -1
- package/src/consumers/validator.js +1 -1
- package/src/core/db/dialect/base-dialect.js +1 -1
- package/src/core/db/dialect/index.js +1 -1
- package/src/core/db/dialect/mysql-dialect.js +1 -1
- package/src/core/db/dialect/oracle-dialect.js +1 -1
- package/src/core/db/dialect/postgres-dialect.js +1 -1
- package/src/core/db/dialect/sqlite-dialect.js +1 -1
- package/src/core/db/flatten-helper.js +1 -1
- package/src/core/db/query-builder-error.js +1 -1
- package/src/core/db/query-builder.js +1 -1
- package/src/core/db/relation-helper.js +1 -1
- package/src/core/handlers/delete_handler.js +1 -1
- package/src/core/handlers/insert_handler.js +1 -1
- package/src/core/handlers/update_handler.js +1 -1
- package/src/core/models/base-model.js +1 -1
- package/src/core/utils/cache-manager.js +1 -1
- package/src/core/utils/component-engine.js +1 -1
- package/src/core/utils/context-builder.js +1 -1
- package/src/core/utils/datetime-formatter.js +1 -1
- package/src/core/utils/datetime-parser.js +1 -1
- package/src/core/utils/db.js +1 -1
- package/src/core/utils/logger.js +1 -1
- package/src/core/utils/payload-loader.js +1 -1
- package/src/core/utils/security-checks.js +1 -1
- package/src/middleware/body-options.js +1 -1
- package/src/middleware/cors.js +1 -1
- package/src/middleware/idempotency.js +1 -1
- package/src/middleware/rate-limiter.js +1 -1
- package/src/middleware/request-logger.js +1 -1
- package/src/middleware/security-headers.js +1 -1
- package/src/models/base-model-mysql.js +1 -1
- package/src/models/base-model-oracle.js +1 -1
- package/src/models/base-model-sqlite.js +1 -1
- package/src/models/base-model.js +1 -1
- package/src/pro/caching/redis-client.js +1 -1
- package/src/pro/caching/redis-helper.js +1 -1
- package/src/pro/consumers/baseConsumer.js +1 -1
- package/src/pro/consumers/declarativeMapper.js +1 -1
- package/src/pro/consumers/handlers/apiHandler.js +1 -1
- package/src/pro/consumers/handlers/consoleHandler.js +1 -1
- package/src/pro/consumers/handlers/databaseHandler.js +1 -1
- package/src/pro/consumers/handlers/index.js +1 -1
- package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
- package/src/pro/consumers/index.js +1 -1
- package/src/pro/consumers/messageTransformer.js +1 -1
- package/src/pro/consumers/validator.js +1 -1
- package/src/pro/database/base-model-mysql.js +1 -1
- package/src/pro/database/base-model-oracle.js +1 -1
- package/src/pro/database/base-model-sqlite.js +1 -1
- package/src/pro/database/db-mysql.js +1 -1
- package/src/pro/database/db-oracle.js +1 -1
- package/src/pro/database/db-sqlite.js +1 -1
- package/src/pro/excel/excel-generator.js +1 -1
- package/src/pro/excel/excel-parser.js +1 -1
- package/src/pro/excel/export-service.js +1 -1
- package/src/pro/excel/export_handler.js +1 -1
- package/src/pro/excel/import-service.js +1 -1
- package/src/pro/excel/import-validator.js +1 -1
- package/src/pro/excel/import_handler.js +1 -1
- package/src/pro/excel/upsert-builder.js +1 -1
- package/src/pro/idgen/idgen-routes.js +1 -1
- package/src/pro/integrations/lookup-resolver.js +1 -1
- package/src/pro/integrations/upload-handler-v2.js +1 -1
- package/src/pro/integrations/upload-handler.js +1 -1
- package/src/pro/integrations/webhook.js +1 -1
- package/src/pro/locking/lock-routes.js +1 -1
- package/src/pro/locking/resource-lock-manager.js +1 -1
- package/src/pro/messaging/kafkaConsumerService.js +1 -1
- package/src/pro/messaging/kafkaService.js +1 -1
- package/src/pro/messaging/messagehubService.js +1 -1
- package/src/pro/messaging/rabbitmqService.js +1 -1
- package/src/pro/scheduler/job-manager.js +1 -1
- package/src/pro/scheduler/job-routes.js +1 -1
- package/src/pro/scheduler/job-validator.js +1 -1
- package/src/pro/storage/base-storage-provider.js +1 -1
- package/src/pro/storage/file-metadata-helper.js +1 -1
- package/src/pro/storage/index.js +1 -1
- package/src/pro/storage/local-storage-provider.js +1 -1
- package/src/pro/storage/s3-storage-provider.js +1 -1
- package/src/pro/storage/upload-cleanup-job.js +1 -1
- package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
- package/src/pro/storage/upload-pending-tracker.js +1 -1
- package/src/pro/websocket/broadcast-helper.js +1 -1
- package/src/pro/websocket/index.js +1 -1
- package/src/pro/websocket/livesync-server.js +1 -1
- package/src/pro/websocket/ws-broadcaster.js +1 -1
- package/src/services/export-service.js +1 -1
- package/src/services/import-service.js +1 -1
- package/src/services/kafkaConsumerService.js +1 -1
- package/src/services/kafkaService.js +1 -1
- package/src/services/messagehubService.js +1 -1
- package/src/services/rabbitmqService.js +1 -1
- package/src/utils/cache-invalidation-registry.js +1 -1
- package/src/utils/cache-manager.js +1 -1
- package/src/utils/component-engine.js +1 -1
- package/src/utils/config-extractor.js +1 -1
- package/src/utils/consumerLogger.js +1 -1
- package/src/utils/context-builder.js +1 -1
- package/src/utils/dashboard-helpers.js +1 -1
- package/src/utils/dateHelper.js +1 -1
- package/src/utils/datetime-formatter.js +1 -1
- package/src/utils/datetime-parser.js +1 -1
- package/src/utils/db-bootstrap.js +1 -1
- package/src/utils/db-mysql.js +1 -1
- package/src/utils/db-oracle.js +1 -1
- package/src/utils/db-sqlite.js +1 -1
- package/src/utils/db.js +1 -1
- package/src/utils/demo-generator.js +1 -1
- package/src/utils/excel-generator.js +1 -1
- package/src/utils/excel-parser.js +1 -1
- package/src/utils/file-watcher.js +1 -1
- package/src/utils/id-generator.js +1 -1
- package/src/utils/idempotency-manager.js +1 -1
- package/src/utils/import-validator.js +1 -1
- package/src/utils/license-client.js +1 -1
- package/src/utils/lock-manager.js +1 -1
- package/src/utils/logger.js +1 -1
- package/src/utils/lookup-resolver.js +1 -1
- package/src/utils/payload-loader.js +1 -1
- package/src/utils/processor-response.js +1 -1
- package/src/utils/rabbitmq.js +1 -1
- package/src/utils/redis-client.js +1 -1
- package/src/utils/redis-helper.js +1 -1
- package/src/utils/request-scope.js +1 -1
- package/src/utils/security-checks.js +1 -1
- package/src/utils/service-resolver.js +1 -1
- package/src/utils/shutdown-coordinator.js +1 -1
- package/src/utils/trusted-keys.js +1 -1
- package/src/utils/upload-handler.js +1 -1
- package/src/utils/upsert-builder.js +1 -1
- package/src/utils/workflow-hook-executor.js +1 -1
- package/generators/metadata/global.json +0 -58
- package/generators/metadata/test-mysql-workbench.json +0 -118
- package/generators/metadata/test-mysql.json +0 -56
- package/generators/metadata/test-oracle-workbench.json +0 -118
- package/generators/metadata/test-oracle.json +0 -56
- package/generators/metadata/test-pg-workbench.json +0 -118
- package/generators/metadata/test-pg.json +0 -56
- package/generators/scripts/obfuscate-source.js +0 -356
- package/generators/scripts/validate-catalog.js +0 -430
- package/generators/scripts/validate-dbschema-catalog.js +0 -708
- package/generators/tests/baseline/mysql/mini_inventory_item/src/models/mini-inventory/item.js +0 -944
- package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
- package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory.js +0 -336
- package/generators/tests/baseline/oracle/mini_inventory_item/src/models/mini-inventory/item.js +0 -1002
- package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
- package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory.js +0 -336
- package/generators/tests/baseline/postgres/mini_inventory_item/src/models/mini-inventory/item.js +0 -1333
- package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory/item.js +0 -1173
- package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory.js +0 -496
- package/generators/tests/fixtures/payloads/custom-sensitive.json +0 -27
- package/generators/tests/fixtures/payloads/dynamic-search-optout.json +0 -23
- package/generators/tests/fixtures/payloads/login-with-password.json +0 -22
- package/generators/tests/fixtures/payloads/order-process.json +0 -52
- package/generators/tests/fixtures/payloads/with-inline-sql.json +0 -26
- package/generators/tests/integration-tahap4b/README.md +0 -145
- package/generators/tests/integration-tahap4b/run-concurrent.js +0 -77
- package/generators/tests/integration-tahap4b/seed.sql +0 -53
- package/generators/tests/integration-tahap4b/verify.sql +0 -110
- package/generators/tests/unit/cli/create-dashboard.test.js +0 -505
- package/generators/tests/unit/cli/create-processor.test.js +0 -319
- package/generators/tests/unit/cli/dispatch-dashboard.test.js +0 -149
- package/generators/tests/unit/lib/dashboard-generator.test.js +0 -895
- package/generators/tests/unit/lib/dashboard-validator.test.js +0 -354
- package/generators/tests/unit/lib/dbschema-kit/apply-executor.test.js +0 -437
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-introspect.test.js +0 -393
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-generate-ddl.test.js +0 -104
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-init.test.js +0 -119
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-list.test.js +0 -48
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-migrate.test.js +0 -175
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-validate.test.js +0 -102
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-models.test.js +0 -43
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/all-schemas-listing.js +0 -84
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/connection-error.js +0 -13
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/empty.js +0 -12
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/multi-schema.js +0 -124
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/single-schema-inventory.js +0 -64
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/two-tables.js +0 -66
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/connection-error.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/partial.js +0 -29
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/rollback.js +0 -26
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/success.js +0 -43
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/audit/events.js +0 -18
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/users.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/connection.test.js +0 -112
- package/generators/tests/unit/lib/dbschema-kit/ddl-generator.test.js +0 -205
- package/generators/tests/unit/lib/dbschema-kit/define-model.test.js +0 -56
- package/generators/tests/unit/lib/dbschema-kit/dialect/index.test.js +0 -46
- package/generators/tests/unit/lib/dbschema-kit/dialect/mysql.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/dialect/oracle.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/dialect/postgres.test.js +0 -131
- package/generators/tests/unit/lib/dbschema-kit/dialect/sqlite.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/driver-loader.test.js +0 -93
- package/generators/tests/unit/lib/dbschema-kit/emitters/create-index.test.js +0 -173
- package/generators/tests/unit/lib/dbschema-kit/emitters/create-table.test.js +0 -376
- package/generators/tests/unit/lib/dbschema-kit/emitters/drop-table.test.js +0 -78
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/invalid-dialect.env +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-dialect.env +0 -5
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-host.env +0 -5
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/oracle-valid.env +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/postgres-valid.env +0 -7
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/sqlite-valid.env +0 -2
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/category.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/item_product.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound.js +0 -24
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound_item.js +0 -28
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/supplier.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/warehouse.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-invalid/orphan.js +0 -17
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/category.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/item_product.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/supplier.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/warehouse.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound.js +0 -24
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound_item.js +0 -28
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/audit/events.js +0 -18
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/public/users.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/extra/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/master/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/bar.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/foo.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/empty-folder/README.md +0 -1
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-export/plain.js +0 -3
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-schema/bad.js +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/legacy-pattern/legacy.js +0 -12
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/audit/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/a/products.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/b/products.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/nested-deep/a/b/c/deep_table.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/.hidden/ignored.js +0 -7
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/supplier.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound_item.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/item_product.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-single/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/integration.test.js +0 -217
- package/generators/tests/unit/lib/dbschema-kit/introspect-mapper.test.js +0 -403
- package/generators/tests/unit/lib/dbschema-kit/ir-builder.test.js +0 -390
- package/generators/tests/unit/lib/dbschema-kit/loader.test.js +0 -128
- package/generators/tests/unit/lib/dbschema-kit/naming.test.js +0 -170
- package/generators/tests/unit/lib/dbschema-kit/parser/shorthand-parser.test.js +0 -237
- package/generators/tests/unit/lib/dbschema-kit/schema-printer.test.js +0 -251
- package/generators/tests/unit/lib/dbschema-kit/statement-modifier.test.js +0 -105
- package/generators/tests/unit/lib/dbschema-kit/statement-splitter.test.js +0 -165
- package/generators/tests/unit/lib/dbschema-kit/topological-sort.test.js +0 -135
- package/generators/tests/unit/lib/dbschema-kit/validator/check-compatibility-validator.test.js +0 -373
- package/generators/tests/unit/lib/dbschema-kit/validator/circular-relation-validator.test.js +0 -454
- package/generators/tests/unit/lib/dbschema-kit/validator/cross-model-validator.test.js +0 -512
- package/generators/tests/unit/lib/dbschema-kit/validator/enhanced-validate-integration.test.js +0 -390
- package/generators/tests/unit/lib/dbschema-kit/validator/naming-convention-validator.test.js +0 -306
- package/generators/tests/unit/lib/dbschema-kit/validator/schema-validator.test.js +0 -443
- package/generators/tests/unit/lib/dbschema-kit/validator/type-compatibility-validator.test.js +0 -440
- package/generators/tests/unit/lib/dbschema-kit/validator/validator-reporter.test.js +0 -172
- package/generators/tests/unit/lib/metadata-manager-dashboard.test.js +0 -256
- package/generators/tests/unit/lib/payload-validator-fieldpolicy.test.js +0 -240
- package/generators/tests/unit/lib/processor-validation-generator.test.js +0 -300
- package/generators/tests/unit/lib/sensitive-field-masker.test.js +0 -170
- package/generators/tests/unit/lib/sql-table-extractor.test.js +0 -119
- package/scripts/generate-integrity-manifest.js +0 -124
- package/scripts/snapshot-cli-contracts.js +0 -194
- package/scripts/verify-publish.js +0 -56
|
@@ -1,708 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* RESTForge - dbschema-kit Catalog Sync Validator
|
|
5
|
-
*
|
|
6
|
-
* Cross-check catalog metadata vs parser source code and spec doc
|
|
7
|
-
* to detect drift between artifacts:
|
|
8
|
-
*
|
|
9
|
-
* 1. Catalog data : generators/lib/templates/dbschema-catalog.js
|
|
10
|
-
* 2. Parser code : generators/lib/dbschema-kit/parser/shorthand-parser.js
|
|
11
|
-
* generators/lib/dbschema-kit/ir-builder.js
|
|
12
|
-
* generators/lib/dbschema-kit/validator/schema-validator.js
|
|
13
|
-
* generators/lib/dbschema-kit/define-model.js
|
|
14
|
-
* 3. Spec doc : <repo-root>/docs/schema-reference/schema-definition.md
|
|
15
|
-
*
|
|
16
|
-
* Levels of validation:
|
|
17
|
-
* Level 1: Catalog structure integrity (required keys, field shape)
|
|
18
|
-
* Level 2: Parser source cross-reference (Set membership match)
|
|
19
|
-
* Level 3: Smoke test (catalog examples execute through actual parser)
|
|
20
|
-
* Level 4: Default value type consistency (parsed type matches field type)
|
|
21
|
-
* Level 5: Spec doc references (each entity is mentioned in markdown)
|
|
22
|
-
*
|
|
23
|
-
* Usage (jalankan dari folder packages/platform):
|
|
24
|
-
* node generators/scripts/validate-dbschema-catalog.js [--strict] [--quiet]
|
|
25
|
-
*
|
|
26
|
-
* Exit codes:
|
|
27
|
-
* 0 = no issues, or only warnings (default)
|
|
28
|
-
* 1 = errors found, or warnings found in --strict mode
|
|
29
|
-
*
|
|
30
|
-
* @module scripts/validate-dbschema-catalog
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
const fs = require('fs');
|
|
34
|
-
const path = require('path');
|
|
35
|
-
|
|
36
|
-
// ============================================================================
|
|
37
|
-
// CONFIG
|
|
38
|
-
// ============================================================================
|
|
39
|
-
|
|
40
|
-
const CATALOG_PATH = path.join(__dirname, '..', 'lib', 'templates', 'dbschema-catalog.js');
|
|
41
|
-
const SHORTHAND_PARSER_PATH = path.join(__dirname, '..', 'lib', 'dbschema-kit', 'parser', 'shorthand-parser.js');
|
|
42
|
-
const IR_BUILDER_PATH = path.join(__dirname, '..', 'lib', 'dbschema-kit', 'ir-builder.js');
|
|
43
|
-
const SCHEMA_VALIDATOR_PATH = path.join(__dirname, '..', 'lib', 'dbschema-kit', 'validator', 'schema-validator.js');
|
|
44
|
-
const DEFINE_MODEL_PATH = path.join(__dirname, '..', 'lib', 'dbschema-kit', 'define-model.js');
|
|
45
|
-
// Spec doc lives at <repo-root>/docs/schema-reference/schema-definition.md (v3 layout).
|
|
46
|
-
// __dirname = packages/platform/generators/scripts → naik 4 level untuk reach repo root.
|
|
47
|
-
const SPEC_DOC_PATH = path.join(__dirname, '..', '..', '..', '..', 'docs', 'schema-reference', 'schema-definition.md');
|
|
48
|
-
|
|
49
|
-
// Mirrors ir-builder.js AUTO_UPDATE_TOKEN_RE_G (used to pre-strip autoUpdate before parser)
|
|
50
|
-
const AUTO_UPDATE_RE = /(?:^|\s)autoUpdate(?=\s|$)/g;
|
|
51
|
-
|
|
52
|
-
// ============================================================================
|
|
53
|
-
// REPORTING
|
|
54
|
-
// ============================================================================
|
|
55
|
-
|
|
56
|
-
const report = {
|
|
57
|
-
errors: [],
|
|
58
|
-
warnings: [],
|
|
59
|
-
info: []
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
function err(msg) { report.errors.push(msg); }
|
|
63
|
-
function warn(msg) { report.warnings.push(msg); }
|
|
64
|
-
function info(msg) { report.info.push(msg); }
|
|
65
|
-
|
|
66
|
-
// ============================================================================
|
|
67
|
-
// PARSE ARGUMENTS
|
|
68
|
-
// ============================================================================
|
|
69
|
-
|
|
70
|
-
function parseArgs() {
|
|
71
|
-
const args = process.argv.slice(2);
|
|
72
|
-
return {
|
|
73
|
-
strict: args.includes('--strict'),
|
|
74
|
-
quiet: args.includes('--quiet')
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ============================================================================
|
|
79
|
-
// HELPER — extract `new Set([...])` contents from source file text
|
|
80
|
-
// ============================================================================
|
|
81
|
-
|
|
82
|
-
function extractSetContents(source, varName) {
|
|
83
|
-
const re = new RegExp(`const\\s+${varName}\\s*=\\s*new Set\\(\\[([^\\]]+)\\]\\)`);
|
|
84
|
-
const m = source.match(re);
|
|
85
|
-
if (!m) return null;
|
|
86
|
-
|
|
87
|
-
const body = m[1];
|
|
88
|
-
const items = [];
|
|
89
|
-
const itemRe = /['"]([a-zA-Z_][a-zA-Z0-9_]*)['"]/g;
|
|
90
|
-
let im;
|
|
91
|
-
while ((im = itemRe.exec(body)) !== null) {
|
|
92
|
-
items.push(im[1]);
|
|
93
|
-
}
|
|
94
|
-
return new Set(items);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function readSource(filePath, label) {
|
|
98
|
-
if (!fs.existsSync(filePath)) {
|
|
99
|
-
err(`${label} not found: ${filePath}`);
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
return fs.readFileSync(filePath, 'utf8');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ============================================================================
|
|
106
|
-
// LEVEL 1: CATALOG STRUCTURE INTEGRITY
|
|
107
|
-
// ============================================================================
|
|
108
|
-
|
|
109
|
-
function checkCatalogStructure(catalog) {
|
|
110
|
-
const requiredKeys = [
|
|
111
|
-
'schemaVersion', 'source', 'summary',
|
|
112
|
-
'defineModelOptions', 'fieldTypes', 'constraints',
|
|
113
|
-
'relationTypes', 'referentialActions', 'checkOperations',
|
|
114
|
-
'auditColumns', 'shorthandSyntax', 'namingRules', 'dialectSupport'
|
|
115
|
-
];
|
|
116
|
-
for (const key of requiredKeys) {
|
|
117
|
-
if (!(key in catalog)) err(`Catalog missing required top-level key: '${key}'`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (!Array.isArray(catalog.defineModelOptions)) err('catalog.defineModelOptions must be an array');
|
|
121
|
-
if (!Array.isArray(catalog.fieldTypes)) err('catalog.fieldTypes must be an array');
|
|
122
|
-
if (!Array.isArray(catalog.constraints)) err('catalog.constraints must be an array');
|
|
123
|
-
if (!Array.isArray(catalog.relationTypes)) err('catalog.relationTypes must be an array');
|
|
124
|
-
if (!Array.isArray(catalog.referentialActions)) err('catalog.referentialActions must be an array');
|
|
125
|
-
if (!Array.isArray(catalog.checkOperations)) err('catalog.checkOperations must be an array');
|
|
126
|
-
if (!Array.isArray(catalog.dialectSupport)) err('catalog.dialectSupport must be an array');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function checkFieldTypesIntegrity(fieldTypes) {
|
|
130
|
-
const requiredFields = ['name', 'description', 'requiresModifier', 'example'];
|
|
131
|
-
const seen = new Set();
|
|
132
|
-
|
|
133
|
-
for (const t of fieldTypes) {
|
|
134
|
-
for (const f of requiredFields) {
|
|
135
|
-
if (!(f in t)) err(`Field type '${t.name || '<unknown>'}' missing field: '${f}'`);
|
|
136
|
-
}
|
|
137
|
-
if (seen.has(t.name)) err(`Duplicate field type name: '${t.name}'`);
|
|
138
|
-
seen.add(t.name);
|
|
139
|
-
|
|
140
|
-
if (t.requiresModifier === true && !t.modifierFormat) {
|
|
141
|
-
err(`Field type '${t.name}': requiresModifier=true but missing modifierFormat`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function checkConstraintsIntegrity(constraints) {
|
|
147
|
-
const requiredFields = ['name', 'kind', 'description', 'example'];
|
|
148
|
-
const validKinds = ['standalone', 'value'];
|
|
149
|
-
const seen = new Set();
|
|
150
|
-
|
|
151
|
-
for (const c of constraints) {
|
|
152
|
-
for (const f of requiredFields) {
|
|
153
|
-
if (!(f in c)) err(`Constraint '${c.name || '<unknown>'}' missing field: '${f}'`);
|
|
154
|
-
}
|
|
155
|
-
if (!validKinds.includes(c.kind)) {
|
|
156
|
-
err(`Constraint '${c.name}': invalid kind '${c.kind}' (must be one of: ${validKinds.join(', ')})`);
|
|
157
|
-
}
|
|
158
|
-
if (seen.has(c.name)) err(`Duplicate constraint name: '${c.name}'`);
|
|
159
|
-
seen.add(c.name);
|
|
160
|
-
|
|
161
|
-
if (c.kind === 'value' && !c.valueFormat) {
|
|
162
|
-
err(`Constraint '${c.name}': kind='value' but missing 'valueFormat'`);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function checkRelationTypesIntegrity(relationTypes) {
|
|
168
|
-
const requiredFields = ['name', 'description', 'requiredFields', 'optionalFields', 'example'];
|
|
169
|
-
const seen = new Set();
|
|
170
|
-
|
|
171
|
-
for (const r of relationTypes) {
|
|
172
|
-
for (const f of requiredFields) {
|
|
173
|
-
if (!(f in r)) err(`Relation type '${r.name || '<unknown>'}' missing field: '${f}'`);
|
|
174
|
-
}
|
|
175
|
-
if (seen.has(r.name)) err(`Duplicate relation type name: '${r.name}'`);
|
|
176
|
-
seen.add(r.name);
|
|
177
|
-
|
|
178
|
-
if (!Array.isArray(r.requiredFields)) err(`Relation type '${r.name}': requiredFields must be array`);
|
|
179
|
-
if (!Array.isArray(r.optionalFields)) err(`Relation type '${r.name}': optionalFields must be array`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function checkReferentialActionsIntegrity(actions) {
|
|
184
|
-
const requiredFields = ['name', 'description', 'appliesTo'];
|
|
185
|
-
const seen = new Set();
|
|
186
|
-
|
|
187
|
-
for (const a of actions) {
|
|
188
|
-
for (const f of requiredFields) {
|
|
189
|
-
if (!(f in a)) err(`Referential action '${a.name || '<unknown>'}' missing field: '${f}'`);
|
|
190
|
-
}
|
|
191
|
-
if (seen.has(a.name)) err(`Duplicate referential action name: '${a.name}'`);
|
|
192
|
-
seen.add(a.name);
|
|
193
|
-
|
|
194
|
-
if (!Array.isArray(a.appliesTo)) err(`Referential action '${a.name}': appliesTo must be array`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function checkCheckOperationsIntegrity(ops) {
|
|
199
|
-
const requiredFields = ['name', 'description', 'valueType', 'example'];
|
|
200
|
-
const seen = new Set();
|
|
201
|
-
|
|
202
|
-
for (const op of ops) {
|
|
203
|
-
for (const f of requiredFields) {
|
|
204
|
-
if (!(f in op)) err(`Check operation '${op.name || '<unknown>'}' missing field: '${f}'`);
|
|
205
|
-
}
|
|
206
|
-
if (seen.has(op.name)) err(`Duplicate check operation name: '${op.name}'`);
|
|
207
|
-
seen.add(op.name);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function checkAuditColumnsIntegrity(auditColumns) {
|
|
212
|
-
if (!auditColumns || typeof auditColumns !== 'object') {
|
|
213
|
-
err('catalog.auditColumns must be an object');
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
if (!Array.isArray(auditColumns.columns)) {
|
|
217
|
-
err('catalog.auditColumns.columns must be an array');
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const required = ['name', 'shorthand', 'nullable', 'purpose'];
|
|
222
|
-
for (const col of auditColumns.columns) {
|
|
223
|
-
for (const f of required) {
|
|
224
|
-
if (!(f in col)) err(`Audit column '${col.name || '<unknown>'}' missing field: '${f}'`);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function checkDialectSupportIntegrity(dialects) {
|
|
230
|
-
const requiredFields = ['name', 'driver', 'booleanStorage'];
|
|
231
|
-
const seen = new Set();
|
|
232
|
-
|
|
233
|
-
for (const d of dialects) {
|
|
234
|
-
for (const f of requiredFields) {
|
|
235
|
-
if (!(f in d)) err(`Dialect '${d.name || '<unknown>'}' missing field: '${f}'`);
|
|
236
|
-
}
|
|
237
|
-
if (seen.has(d.name)) err(`Duplicate dialect name: '${d.name}'`);
|
|
238
|
-
seen.add(d.name);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// ============================================================================
|
|
243
|
-
// LEVEL 2: PARSER SOURCE CROSS-REFERENCE (GROUND TRUTH)
|
|
244
|
-
// ============================================================================
|
|
245
|
-
|
|
246
|
-
function checkFieldTypesVsParser(catalog) {
|
|
247
|
-
const source = readSource(SHORTHAND_PARSER_PATH, 'Shorthand parser');
|
|
248
|
-
if (!source) return;
|
|
249
|
-
|
|
250
|
-
const parserTypes = extractSetContents(source, 'VALID_TYPES');
|
|
251
|
-
if (!parserTypes) {
|
|
252
|
-
warn('Could not extract VALID_TYPES from shorthand-parser.js (regex pattern may need update)');
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const catalogTypes = new Set(catalog.fieldTypes.map(t => t.name));
|
|
257
|
-
|
|
258
|
-
for (const t of parserTypes) {
|
|
259
|
-
if (!catalogTypes.has(t)) {
|
|
260
|
-
err(`Parser drift: type '${t}' exists in VALID_TYPES but missing from catalog.fieldTypes`);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
for (const t of catalogTypes) {
|
|
265
|
-
if (!parserTypes.has(t)) {
|
|
266
|
-
err(`Parser drift: type '${t}' in catalog.fieldTypes but missing from parser VALID_TYPES`);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function checkConstraintsVsParser(catalog) {
|
|
272
|
-
const parserSrc = readSource(SHORTHAND_PARSER_PATH, 'Shorthand parser');
|
|
273
|
-
if (!parserSrc) return;
|
|
274
|
-
|
|
275
|
-
const standaloneFromParser = extractSetContents(parserSrc, 'STANDALONE_CONSTRAINTS') || new Set();
|
|
276
|
-
const valueFromParser = extractSetContents(parserSrc, 'VALUE_CONSTRAINTS') || new Set();
|
|
277
|
-
|
|
278
|
-
// autoUpdate is pre-processed in ir-builder.js, also a valid constraint at the API surface
|
|
279
|
-
let irHasAutoUpdate = false;
|
|
280
|
-
const irSrc = readSource(IR_BUILDER_PATH, 'IR builder');
|
|
281
|
-
if (irSrc) irHasAutoUpdate = /AUTO_UPDATE_TOKEN_RE/.test(irSrc);
|
|
282
|
-
|
|
283
|
-
const parserConstraints = new Set([...standaloneFromParser, ...valueFromParser]);
|
|
284
|
-
if (irHasAutoUpdate) parserConstraints.add('autoUpdate');
|
|
285
|
-
|
|
286
|
-
const catalogConstraintNames = new Set(catalog.constraints.map(c => c.name));
|
|
287
|
-
|
|
288
|
-
for (const c of parserConstraints) {
|
|
289
|
-
if (!catalogConstraintNames.has(c)) {
|
|
290
|
-
err(`Parser drift: constraint '${c}' valid in parser but missing from catalog.constraints`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
for (const c of catalogConstraintNames) {
|
|
295
|
-
if (!parserConstraints.has(c)) {
|
|
296
|
-
err(`Parser drift: constraint '${c}' in catalog but not recognized by parser or ir-builder`);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// Verify kind matches parser STANDALONE_CONSTRAINTS / VALUE_CONSTRAINTS partitioning
|
|
301
|
-
for (const c of catalog.constraints) {
|
|
302
|
-
if (standaloneFromParser.has(c.name) && c.kind !== 'standalone') {
|
|
303
|
-
err(`Constraint '${c.name}': kind='${c.kind}' in catalog but is STANDALONE in parser`);
|
|
304
|
-
}
|
|
305
|
-
if (valueFromParser.has(c.name) && c.kind !== 'value') {
|
|
306
|
-
err(`Constraint '${c.name}': kind='${c.kind}' in catalog but is VALUE in parser`);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function checkRelationTypesVsValidator(catalog) {
|
|
312
|
-
const source = readSource(SCHEMA_VALIDATOR_PATH, 'Schema validator');
|
|
313
|
-
if (!source) return;
|
|
314
|
-
|
|
315
|
-
const validatorTypes = extractSetContents(source, 'VALID_RELATION_TYPES');
|
|
316
|
-
if (!validatorTypes) {
|
|
317
|
-
warn('Could not extract VALID_RELATION_TYPES from schema-validator.js');
|
|
318
|
-
} else {
|
|
319
|
-
const catalogTypes = new Set(catalog.relationTypes.map(r => r.name));
|
|
320
|
-
|
|
321
|
-
for (const t of validatorTypes) {
|
|
322
|
-
if (!catalogTypes.has(t)) {
|
|
323
|
-
err(`Validator drift: relation type '${t}' valid in VALID_RELATION_TYPES but missing from catalog.relationTypes`);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
for (const t of catalogTypes) {
|
|
327
|
-
if (!validatorTypes.has(t)) {
|
|
328
|
-
err(`Validator drift: relation type '${t}' in catalog but not in VALID_RELATION_TYPES`);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Validator throws if localKey is missing — so it must be in requiredFields, not optional
|
|
334
|
-
const requiresLocalKey = /missing\s+'localKey'/.test(source);
|
|
335
|
-
if (requiresLocalKey) {
|
|
336
|
-
for (const r of catalog.relationTypes) {
|
|
337
|
-
if (r.optionalFields.includes('localKey')) {
|
|
338
|
-
err(`Relation type '${r.name}': validator throws on missing 'localKey' but catalog marks it as OPTIONAL`);
|
|
339
|
-
}
|
|
340
|
-
if (!r.requiredFields.includes('localKey')) {
|
|
341
|
-
err(`Relation type '${r.name}': validator requires 'localKey' but catalog does not list it in requiredFields`);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// The validator only checks typeof rel.references === 'string', so it expects a bare column name
|
|
347
|
-
// Catalog examples that show 'references: "table(column)"' would mislead consumers
|
|
348
|
-
for (const r of catalog.relationTypes) {
|
|
349
|
-
if (typeof r.example !== 'string') continue;
|
|
350
|
-
const refMatch = r.example.match(/references:\s*["']([^"']+)["']/);
|
|
351
|
-
if (refMatch && /\(.*\)/.test(refMatch[1])) {
|
|
352
|
-
err(`Relation type '${r.name}': example shows 'references: "${refMatch[1]}"' (table(column) form) but validator expects a bare column name`);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function checkReferentialActionsVsValidator(catalog) {
|
|
358
|
-
const source = readSource(SCHEMA_VALIDATOR_PATH, 'Schema validator');
|
|
359
|
-
if (!source) return;
|
|
360
|
-
|
|
361
|
-
const validatorActions = extractSetContents(source, 'VALID_REFERENTIAL_ACTIONS');
|
|
362
|
-
if (!validatorActions) {
|
|
363
|
-
warn('Could not extract VALID_REFERENTIAL_ACTIONS from schema-validator.js');
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const catalogActions = new Set(catalog.referentialActions.map(a => a.name));
|
|
368
|
-
|
|
369
|
-
for (const a of validatorActions) {
|
|
370
|
-
if (!catalogActions.has(a)) {
|
|
371
|
-
err(`Validator drift: referential action '${a}' valid in validator but missing from catalog`);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
for (const a of catalogActions) {
|
|
375
|
-
if (!validatorActions.has(a)) {
|
|
376
|
-
err(`Validator drift: referential action '${a}' in catalog but not in VALID_REFERENTIAL_ACTIONS`);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function checkCheckOperationsVsIrBuilder(catalog) {
|
|
382
|
-
const source = readSource(IR_BUILDER_PATH, 'IR builder');
|
|
383
|
-
if (!source) return;
|
|
384
|
-
|
|
385
|
-
const irOps = extractSetContents(source, 'VALID_CHECK_OPS');
|
|
386
|
-
if (!irOps) {
|
|
387
|
-
warn('Could not extract VALID_CHECK_OPS from ir-builder.js');
|
|
388
|
-
} else {
|
|
389
|
-
const catalogOps = new Set(catalog.checkOperations.map(o => o.name));
|
|
390
|
-
|
|
391
|
-
for (const o of irOps) {
|
|
392
|
-
if (!catalogOps.has(o)) {
|
|
393
|
-
err(`IR drift: check op '${o}' valid in VALID_CHECK_OPS but missing from catalog`);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
for (const o of catalogOps) {
|
|
397
|
-
if (!irOps.has(o)) {
|
|
398
|
-
err(`IR drift: check op '${o}' in catalog but not in VALID_CHECK_OPS`);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// User-facing format is `{ field, <op>: value }` (operator as key).
|
|
404
|
-
// The `{ op, field, value }` shape is the IR output, not the user input.
|
|
405
|
-
for (const op of catalog.checkOperations) {
|
|
406
|
-
if (typeof op.example === 'string' && /\bop\s*:\s*['"]/.test(op.example)) {
|
|
407
|
-
err(`Check op '${op.name}': example uses IR output shape '{ op: ... }' instead of user input shape '{ field, ${op.name}: ... }'`);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Scan ALL catalog sections for IR check anti-pattern. Catches cases where
|
|
413
|
-
// description or example anywhere in the catalog (not just checkOperations)
|
|
414
|
-
// uses the internal IR shape `{ op, field, value }` instead of user input
|
|
415
|
-
// shape `{ field, <op>: value }`. This complements checkCheckOperationsVsIrBuilder
|
|
416
|
-
// which only scans the checkOperations section itself.
|
|
417
|
-
function checkAllCatalogForIrCheckPattern(catalog) {
|
|
418
|
-
const opValueRe = /\bop\s*:\s*['"](?:in|eq|neq|gt|gte|lt|lte)['"]/;
|
|
419
|
-
const descShapeRe = /\{[^}]*\bop\b[^}]*\bfield\b[^}]*\bvalue\b[^}]*\}/;
|
|
420
|
-
|
|
421
|
-
const arraySections = [
|
|
422
|
-
'defineModelOptions', 'fieldTypes', 'constraints',
|
|
423
|
-
'relationTypes', 'referentialActions', 'dialectSupport'
|
|
424
|
-
// Skip checkOperations — already covered by checkCheckOperationsVsIrBuilder
|
|
425
|
-
];
|
|
426
|
-
|
|
427
|
-
for (const sectionName of arraySections) {
|
|
428
|
-
const items = catalog[sectionName];
|
|
429
|
-
if (!Array.isArray(items)) continue;
|
|
430
|
-
|
|
431
|
-
for (const item of items) {
|
|
432
|
-
const label = item.name ? `${sectionName}.${item.name}` : sectionName;
|
|
433
|
-
|
|
434
|
-
if (typeof item.example === 'string' && opValueRe.test(item.example)) {
|
|
435
|
-
err(`${label}.example uses IR check shape '{ op: "...", field, value }'. Use user input shape '{ field, <op>: <value> }' instead.`);
|
|
436
|
-
}
|
|
437
|
-
if (typeof item.description === 'string' && descShapeRe.test(item.description)) {
|
|
438
|
-
err(`${label}.description describes IR check shape '{ ..., op, field, value, ... }'. User input shape uses operator-as-key.`);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// Also scan shorthandSyntax.examples meaning strings
|
|
444
|
-
if (catalog.shorthandSyntax && Array.isArray(catalog.shorthandSyntax.examples)) {
|
|
445
|
-
for (const ex of catalog.shorthandSyntax.examples) {
|
|
446
|
-
if (typeof ex.meaning === 'string' && opValueRe.test(ex.meaning)) {
|
|
447
|
-
err(`shorthandSyntax.examples meaning uses IR check shape: '${ex.meaning}'`);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
function checkDefineModelSignature(catalog) {
|
|
454
|
-
const source = readSource(DEFINE_MODEL_PATH, 'define-model');
|
|
455
|
-
if (!source) return;
|
|
456
|
-
|
|
457
|
-
const isPositional = /function\s+defineModel\s*\(\s*tableName\s*,\s*options\s*\)/.test(source);
|
|
458
|
-
if (!isPositional) {
|
|
459
|
-
warn('Could not verify defineModel signature in define-model.js (regex pattern may need update)');
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
const tableNameOption = catalog.defineModelOptions.find(o => o.name === 'tableName');
|
|
464
|
-
if (tableNameOption) {
|
|
465
|
-
err(`Signature drift: 'tableName' is a positional argument in defineModel(tableName, options) but catalog.defineModelOptions lists it as an options property`);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// ============================================================================
|
|
470
|
-
// LEVEL 3: SMOKE TEST — execute catalog examples through actual parser
|
|
471
|
-
// ============================================================================
|
|
472
|
-
|
|
473
|
-
function collectShorthandExamples(catalog) {
|
|
474
|
-
const examples = [];
|
|
475
|
-
|
|
476
|
-
for (const t of catalog.fieldTypes) {
|
|
477
|
-
if (typeof t.example === 'string') {
|
|
478
|
-
examples.push({ source: `fieldTypes.${t.name}.example`, input: t.example });
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
for (const c of catalog.constraints) {
|
|
482
|
-
if (typeof c.example === 'string') {
|
|
483
|
-
examples.push({ source: `constraints.${c.name}.example`, input: c.example });
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
if (catalog.shorthandSyntax && Array.isArray(catalog.shorthandSyntax.examples)) {
|
|
487
|
-
for (const ex of catalog.shorthandSyntax.examples) {
|
|
488
|
-
if (typeof ex.input === 'string') {
|
|
489
|
-
examples.push({ source: `shorthandSyntax.examples[${JSON.stringify(ex.input)}]`, input: ex.input });
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
if (catalog.auditColumns && Array.isArray(catalog.auditColumns.columns)) {
|
|
494
|
-
for (const col of catalog.auditColumns.columns) {
|
|
495
|
-
if (typeof col.shorthand === 'string') {
|
|
496
|
-
examples.push({ source: `auditColumns.${col.name}.shorthand`, input: col.shorthand });
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
return examples;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
function loadParser() {
|
|
505
|
-
try {
|
|
506
|
-
const mod = require(SHORTHAND_PARSER_PATH);
|
|
507
|
-
if (typeof mod.parseFieldShorthand !== 'function') {
|
|
508
|
-
err('shorthand-parser.js does not export parseFieldShorthand');
|
|
509
|
-
return null;
|
|
510
|
-
}
|
|
511
|
-
return mod.parseFieldShorthand;
|
|
512
|
-
} catch (e) {
|
|
513
|
-
err(`Could not load shorthand-parser.js: ${e.message}`);
|
|
514
|
-
return null;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
function checkExamplesParseable(catalog, parseFieldShorthand) {
|
|
519
|
-
if (!parseFieldShorthand) return;
|
|
520
|
-
const examples = collectShorthandExamples(catalog);
|
|
521
|
-
|
|
522
|
-
for (const { source, input } of examples) {
|
|
523
|
-
const cleaned = input.replace(AUTO_UPDATE_RE, ' ').trim();
|
|
524
|
-
if (cleaned === '') continue;
|
|
525
|
-
|
|
526
|
-
try {
|
|
527
|
-
parseFieldShorthand(cleaned, '_smoke_test_');
|
|
528
|
-
} catch (e) {
|
|
529
|
-
err(`Smoke test FAIL: ${source} — input '${input}' threw: ${e.message}`);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// ============================================================================
|
|
535
|
-
// LEVEL 4: DEFAULT VALUE TYPE CONSISTENCY
|
|
536
|
-
// ============================================================================
|
|
537
|
-
|
|
538
|
-
function checkDefaultValueTypeConsistency(catalog, parseFieldShorthand) {
|
|
539
|
-
if (!parseFieldShorthand) return;
|
|
540
|
-
|
|
541
|
-
const examples = collectShorthandExamples(catalog).filter(e => e.input.includes('default:'));
|
|
542
|
-
|
|
543
|
-
for (const { source, input } of examples) {
|
|
544
|
-
let parsed;
|
|
545
|
-
try {
|
|
546
|
-
const cleaned = input.replace(AUTO_UPDATE_RE, ' ').trim();
|
|
547
|
-
parsed = parseFieldShorthand(cleaned, '_type_test_');
|
|
548
|
-
} catch {
|
|
549
|
-
continue; // caught by smoke test
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
if (!parsed || !parsed.default || parsed.default.kind !== 'literal') continue;
|
|
553
|
-
const valueType = typeof parsed.default.value;
|
|
554
|
-
|
|
555
|
-
if (parsed.type === 'boolean' && valueType !== 'boolean') {
|
|
556
|
-
warn(`${source}: type 'boolean' with default '${input}' parses default as ${valueType}, expected boolean. Use 'default:true' (raw, no quote) instead.`);
|
|
557
|
-
}
|
|
558
|
-
if ((parsed.type === 'integer' || parsed.type === 'bigint' || parsed.type === 'decimal') && valueType !== 'number') {
|
|
559
|
-
warn(`${source}: type '${parsed.type}' with default '${input}' parses default as ${valueType}, expected number. Use raw form like 'default:0' (no quote) instead.`);
|
|
560
|
-
}
|
|
561
|
-
if ((parsed.type === 'string' || parsed.type === 'text') && valueType !== 'string') {
|
|
562
|
-
warn(`${source}: type '${parsed.type}' with default '${input}' parses default as ${valueType}, expected string. Use quoted form like 'default:\\'value\\'' instead.`);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// ============================================================================
|
|
568
|
-
// LEVEL 5: SPEC DOC REFERENCE
|
|
569
|
-
// ============================================================================
|
|
570
|
-
|
|
571
|
-
function checkSpecDocReferences(catalog) {
|
|
572
|
-
if (!fs.existsSync(SPEC_DOC_PATH)) {
|
|
573
|
-
warn(`Spec doc not found: ${SPEC_DOC_PATH}`);
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
const doc = fs.readFileSync(SPEC_DOC_PATH, 'utf8');
|
|
578
|
-
|
|
579
|
-
const checks = [
|
|
580
|
-
{ items: catalog.fieldTypes, label: 'field type' },
|
|
581
|
-
{ items: catalog.constraints, label: 'constraint' },
|
|
582
|
-
{ items: catalog.relationTypes, label: 'relation type' },
|
|
583
|
-
{ items: catalog.referentialActions, label: 'referential action' },
|
|
584
|
-
{ items: catalog.checkOperations, label: 'check op' },
|
|
585
|
-
{ items: catalog.dialectSupport, label: 'dialect' }
|
|
586
|
-
];
|
|
587
|
-
|
|
588
|
-
for (const { items, label } of checks) {
|
|
589
|
-
for (const it of items) {
|
|
590
|
-
const re = new RegExp(`\\b${it.name}\\b`, 'i');
|
|
591
|
-
if (!re.test(doc)) warn(`Spec doc: ${label} '${it.name}' not referenced in schema-definition.md`);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// ============================================================================
|
|
597
|
-
// MAIN
|
|
598
|
-
// ============================================================================
|
|
599
|
-
|
|
600
|
-
function printReport(quiet) {
|
|
601
|
-
const lines = [];
|
|
602
|
-
|
|
603
|
-
lines.push('');
|
|
604
|
-
lines.push('================================================================');
|
|
605
|
-
lines.push(' dbschema-kit Catalog Sync Validator');
|
|
606
|
-
lines.push('================================================================');
|
|
607
|
-
lines.push('');
|
|
608
|
-
|
|
609
|
-
if (report.errors.length > 0) {
|
|
610
|
-
lines.push(`ERRORS (${report.errors.length}):`);
|
|
611
|
-
for (const e of report.errors) lines.push(` [X] ${e}`);
|
|
612
|
-
lines.push('');
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
if (report.warnings.length > 0) {
|
|
616
|
-
lines.push(`WARNINGS (${report.warnings.length}):`);
|
|
617
|
-
for (const w of report.warnings) lines.push(` [!] ${w}`);
|
|
618
|
-
lines.push('');
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
if (!quiet && report.info.length > 0) {
|
|
622
|
-
lines.push(`INFO (${report.info.length}):`);
|
|
623
|
-
for (const i of report.info) lines.push(` [i] ${i}`);
|
|
624
|
-
lines.push('');
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
lines.push('----------------------------------------------------------------');
|
|
628
|
-
lines.push(' Summary');
|
|
629
|
-
lines.push('----------------------------------------------------------------');
|
|
630
|
-
lines.push(` Errors : ${report.errors.length}`);
|
|
631
|
-
lines.push(` Warnings: ${report.warnings.length}`);
|
|
632
|
-
lines.push(` Info : ${report.info.length}`);
|
|
633
|
-
lines.push('');
|
|
634
|
-
|
|
635
|
-
if (report.errors.length === 0 && report.warnings.length === 0) {
|
|
636
|
-
lines.push(' Status: PASS — catalog is in sync with parser source and spec doc.');
|
|
637
|
-
} else if (report.errors.length === 0) {
|
|
638
|
-
lines.push(' Status: PASS WITH WARNINGS — review warnings above.');
|
|
639
|
-
} else {
|
|
640
|
-
lines.push(' Status: FAIL — fix errors before commit.');
|
|
641
|
-
}
|
|
642
|
-
lines.push('');
|
|
643
|
-
|
|
644
|
-
console.log(lines.join('\n'));
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
function main() {
|
|
648
|
-
const opts = parseArgs();
|
|
649
|
-
|
|
650
|
-
let catalog;
|
|
651
|
-
try {
|
|
652
|
-
({ DBSCHEMA_CATALOG: catalog } = require(CATALOG_PATH));
|
|
653
|
-
} catch (e) {
|
|
654
|
-
console.error(`Failed to load catalog from ${CATALOG_PATH}`);
|
|
655
|
-
console.error(e.message);
|
|
656
|
-
process.exit(1);
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
info(`Catalog loaded from: ${path.relative(process.cwd(), CATALOG_PATH)}`);
|
|
660
|
-
info(`Schema version: ${catalog.schemaVersion}`);
|
|
661
|
-
info(
|
|
662
|
-
`Field types: ${catalog.fieldTypes ? catalog.fieldTypes.length : 0}, ` +
|
|
663
|
-
`Constraints: ${catalog.constraints ? catalog.constraints.length : 0}, ` +
|
|
664
|
-
`Relation types: ${catalog.relationTypes ? catalog.relationTypes.length : 0}, ` +
|
|
665
|
-
`Check ops: ${catalog.checkOperations ? catalog.checkOperations.length : 0}`
|
|
666
|
-
);
|
|
667
|
-
|
|
668
|
-
// Level 1: catalog structural integrity
|
|
669
|
-
checkCatalogStructure(catalog);
|
|
670
|
-
if (Array.isArray(catalog.fieldTypes)) checkFieldTypesIntegrity(catalog.fieldTypes);
|
|
671
|
-
if (Array.isArray(catalog.constraints)) checkConstraintsIntegrity(catalog.constraints);
|
|
672
|
-
if (Array.isArray(catalog.relationTypes)) checkRelationTypesIntegrity(catalog.relationTypes);
|
|
673
|
-
if (Array.isArray(catalog.referentialActions)) checkReferentialActionsIntegrity(catalog.referentialActions);
|
|
674
|
-
if (Array.isArray(catalog.checkOperations)) checkCheckOperationsIntegrity(catalog.checkOperations);
|
|
675
|
-
if (catalog.auditColumns) checkAuditColumnsIntegrity(catalog.auditColumns);
|
|
676
|
-
if (Array.isArray(catalog.dialectSupport)) checkDialectSupportIntegrity(catalog.dialectSupport);
|
|
677
|
-
|
|
678
|
-
// Stop early on structural failure — downstream checks would be misleading
|
|
679
|
-
if (report.errors.length > 0) {
|
|
680
|
-
printReport(opts.quiet);
|
|
681
|
-
process.exit(1);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// Level 2: parser source cross-reference
|
|
685
|
-
checkFieldTypesVsParser(catalog);
|
|
686
|
-
checkConstraintsVsParser(catalog);
|
|
687
|
-
checkRelationTypesVsValidator(catalog);
|
|
688
|
-
checkReferentialActionsVsValidator(catalog);
|
|
689
|
-
checkCheckOperationsVsIrBuilder(catalog);
|
|
690
|
-
checkAllCatalogForIrCheckPattern(catalog);
|
|
691
|
-
checkDefineModelSignature(catalog);
|
|
692
|
-
|
|
693
|
-
// Level 3 + 4: parser smoke test + default value type consistency
|
|
694
|
-
const parseFieldShorthand = loadParser();
|
|
695
|
-
checkExamplesParseable(catalog, parseFieldShorthand);
|
|
696
|
-
checkDefaultValueTypeConsistency(catalog, parseFieldShorthand);
|
|
697
|
-
|
|
698
|
-
// Level 5: spec doc references
|
|
699
|
-
checkSpecDocReferences(catalog);
|
|
700
|
-
|
|
701
|
-
printReport(opts.quiet);
|
|
702
|
-
|
|
703
|
-
if (report.errors.length > 0) process.exit(1);
|
|
704
|
-
if (opts.strict && report.warnings.length > 0) process.exit(1);
|
|
705
|
-
process.exit(0);
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
main();
|