From 801956aa6eeda8e2eba90ee653a1d0bd572fa9e5 Mon Sep 17 00:00:00 2001 From: DavidAD Date: Tue, 6 Jan 2026 10:27:32 -0700 Subject: [PATCH 1/6] Add ACP Attempts, Primer, and Sync schemas to catalog (#5239) * Add ACP Attempts, Primer, and Sync schemas to catalog Adds three additional AI Context Protocol (ACP) schemas: - ACP Attempts: Debug session tracking for AI-assisted debugging workflows - ACP Primer: Primer definitions for AI context bootstrapping - ACP Sync: Tool synchronization configuration for AI assistants This complements the existing ACP schemas (Cache, Config, Variables) added in #5233. Project: https://acp-protocol.dev Specification: https://github.com/acp-protocol/acp-spec * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/api/json/catalog.json | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/api/json/catalog.json b/src/api/json/catalog.json index 089a3d83660..f698b12c8ce 100644 --- a/src/api/json/catalog.json +++ b/src/api/json/catalog.json @@ -193,6 +193,12 @@ "11.2.0": "https://www.schemastore.org/abc-supply-plan-11.2.0.json" } }, + { + "name": "ACP Attempts", + "description": "AI Context Protocol debug session tracking file", + "fileMatch": ["**/.acp/acp.attempts.json", "acp.attempts.json"], + "url": "https://acp-protocol.dev/schemas/v1/attempts.schema.json" + }, { "name": "ACP Cache File", "description": "AI Context Protocol cache file format for storing indexed codebase metadata", @@ -205,6 +211,18 @@ "fileMatch": [".acp.config.json"], "url": "https://acp-protocol.dev/schemas/v1/config.schema.json" }, + { + "name": "ACP Primer", + "description": "AI Context Protocol primer definition for AI context bootstrapping", + "fileMatch": ["primer.json", "*.primer.json", "primer.defaults.json"], + "url": "https://acp-protocol.dev/schemas/v1/primer.schema.json" + }, + { + "name": "ACP Sync", + "description": "AI Context Protocol tool synchronization configuration", + "fileMatch": ["**/.acp/acp.sync.json", "acp.sync.json"], + "url": "https://acp-protocol.dev/schemas/v1/sync.schema.json" + }, { "name": "ACP Variables File", "description": "AI Context Protocol variables file for reusable context variables", @@ -4289,7 +4307,7 @@ }, { "name": "nest-cli", - "description": "A progressive Node.js framework for building efficient and scalable server-side applications 🚀", + "description": "A progressive Node.js framework for building efficient and scalable server-side applications \ud83d\ude80", "fileMatch": [ ".nestcli.json", ".nest-cli.json", @@ -5132,7 +5150,7 @@ }, { "name": ".putout.json", - "description": "🐊Putout configuration file", + "description": "\ud83d\udc0aPutout configuration file", "fileMatch": [".putout.json"], "url": "https://www.schemastore.org/putout.json" }, @@ -5369,7 +5387,7 @@ }, { "name": "JSON Resume", - "description": "JSON résumé files", + "description": "JSON r\u00e9sum\u00e9 files", "fileMatch": [ "**/resume.json", "**/*.resume.json", @@ -6193,7 +6211,7 @@ }, { "name": "Tombi", - "description": "Tombi (鳶) is a toolkit for TOML; providing a formatter/linter and language server", + "description": "Tombi (\u9cf6) is a toolkit for TOML; providing a formatter/linter and language server", "fileMatch": ["tombi.toml", "**/tombi/config.toml"], "url": "https://www.schemastore.org/tombi.json" }, @@ -6261,7 +6279,7 @@ }, { "name": "TrueScript for *.tscript files", - "description": "The Ultimate Script Language for monday.com - © 2024 MakeITSimple", + "description": "The Ultimate Script Language for monday.com - \u00a9 2024 MakeITSimple", "fileMatch": ["*.tscript", "*.tscript.yaml", "*.tscript.yml"], "url": "https://www.schemastore.org/truescript.json", "versions": { @@ -6797,7 +6815,7 @@ }, { "name": "huskyrc", - "description": "Husky can prevent bad `git commit`, `git push` and more 🐶 woof!", + "description": "Husky can prevent bad `git commit`, `git push` and more \ud83d\udc36 woof!", "fileMatch": [".huskyrc", ".huskyrc.json"], "url": "https://www.schemastore.org/huskyrc.json" }, @@ -7017,8 +7035,8 @@ "url": "https://www.schemastore.org/container-structure-test.json" }, { - "name": "Žinoma", - "description": "Žinoma incremental build configuration", + "name": "\u017dinoma", + "description": "\u017dinoma incremental build configuration", "fileMatch": ["zinoma.yml"], "url": "https://github.com/fbecart/zinoma/releases/latest/download/zinoma-schema.json" }, @@ -7269,7 +7287,7 @@ }, { "name": "Render Blueprints", - "description": "Blueprints are Render’s infrastructure-as-code model for defining, deploying, and managing multiple resources with a single YAML file", + "description": "Blueprints are Render\u2019s infrastructure-as-code model for defining, deploying, and managing multiple resources with a single YAML file", "fileMatch": ["**/*render.yaml"], "url": "https://render.com/schema/render.yaml.json" }, @@ -8985,7 +9003,7 @@ }, { "name": "Deployah Configuration", - "description": "CLI tool that makes Kubernetes deployments effortless—no Helm or K8s expertise required", + "description": "CLI tool that makes Kubernetes deployments effortless\u2014no Helm or K8s expertise required", "fileMatch": [ "deployah.yaml", "deployah.yml", From afc29264ad59993268cc83b3208538d5feebfed6 Mon Sep 17 00:00:00 2001 From: Rebaz Raouf Date: Tue, 6 Jan 2026 20:27:53 +0300 Subject: [PATCH 2/6] Update .macro.json in catalog.json (#5240) --- src/api/json/catalog.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/json/catalog.json b/src/api/json/catalog.json index f698b12c8ce..b29dfb8f52c 100644 --- a/src/api/json/catalog.json +++ b/src/api/json/catalog.json @@ -7753,9 +7753,9 @@ "url": "https://raw.githubusercontent.com/loft-sh/devspace/main/devspace-schema.json" }, { - "name": ".macro.json", + "name": "macro.json", "description": "Macro configuration file", - "fileMatch": [".macro.json"], + "fileMatch": ["macro.json"], "url": "https://raw.githubusercontent.com/rebaz94/macro_kit/refs/heads/main/macro_schema.json" }, { From 384d70c8cbcfb2d83554420f4c7e5448385e5f2e Mon Sep 17 00:00:00 2001 From: Rob Gonnella Date: Tue, 6 Jan 2026 12:30:33 -0500 Subject: [PATCH 3/6] adds releasaurus schema to the catalog (#5261) * adds releasaurus schema to the catalog * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Rob Gonnella Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/api/json/catalog.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api/json/catalog.json b/src/api/json/catalog.json index b29dfb8f52c..8fb68dd6117 100644 --- a/src/api/json/catalog.json +++ b/src/api/json/catalog.json @@ -13,6 +13,12 @@ ], "url": "https://raw.githubusercontent.com/teneplaysofficial/release-hub/main/schema/release-hub.schema.json" }, + { + "name": "Releasaurus Config", + "description": "Configuration file for Releasaurus", + "fileMatch": ["releasaurus.toml"], + "url": "https://raw.githubusercontent.com/robgonnella/releasaurus/refs/heads/main/schema/schema.json" + }, { "name": "Bacon config", "description": "Bacon configuration file", From aec62c44b474c3c3b659c8806010408b32689a1e Mon Sep 17 00:00:00 2001 From: kzrnm Date: Wed, 7 Jan 2026 02:33:35 +0900 Subject: [PATCH 4/6] (pyproject) Update poe schema (#5264) * (poe) Update envfile * (poe) ignore_fail * (poe) choices option * (poe) uv executor * (poe) fix ref_task --- src/schemas/json/partial-poe.json | 236 +++++++++++++++++++++++++----- 1 file changed, 201 insertions(+), 35 deletions(-) diff --git a/src/schemas/json/partial-poe.json b/src/schemas/json/partial-poe.json index 913fe9c116b..f16bcabc132 100644 --- a/src/schemas/json/partial-poe.json +++ b/src/schemas/json/partial-poe.json @@ -67,6 +67,15 @@ "description": "Indicates if the argument is positional.", "type": "boolean" }, + "choices": { + "description": "Constrain the accepted values for an argument to a fixed set.", + "oneOf": [ + { "items": { "type": "string" } }, + { "items": { "type": "integer" } }, + { "items": { "type": "number" } } + ], + "type": "array" + }, "required": { "description": "Indicates if the argument is required.", "type": "boolean" @@ -160,6 +169,27 @@ "then": { "not": { "required": ["capture_stdout"] } }, "type": "object" }, + "ignore_fail_exec_option": { + "description": "Return exit code 0 even if the task fails, or specify a list of task exit codes to ignore.", + "examples": [true], + "oneOf": [ + { "type": "array", "items": { "type": "integer" } }, + { "type": "boolean" } + ] + }, + "ignore_fail_tasks_option": { + "description": "If set, the sequence will continue running even if one of the tasks fails.", + "examples": [true, "return_zero", "return_non_zero"], + "oneOf": [ + { + "type": "boolean" + }, + { + "enum": ["return_zero", "return_non_zero"], + "type": "string" + } + ] + }, "env_option": { "additionalProperties": false, "patternProperties": { @@ -185,35 +215,160 @@ "description": "Provide one or more env files to be loaded before running this task. If an array is provided, files will be loaded in the given order.", "oneOf": [ { - "description": "The name or relative path to a single env file.", - "type": "string" + "$ref": "#/definitions/envfile_option/definitions/envfile" }, { - "description": "An array of names or relative paths to env files which will be loaded in the given order.", - "items": { - "description": "The name or relative path to an env file.", - "type": "string" + "properties": { + "expected": { + "$ref": "#/definitions/envfile_option/definitions/envfile", + "description": "Provide one or more env files to be loaded before running this task. Emit a warning if any specified envfile is missing." + }, + "optional": { + "$ref": "#/definitions/envfile_option/definitions/envfile", + "description": "Provide one or more env files to be loaded before running this task. Do not emit a warning even if a specified envfile is missing." + } }, - "type": "array" + "type": "object" } - ] + ], + "definitions": { + "envfile": { + "oneOf": [ + { + "description": "The name or relative path to a single env file.", + "type": "string" + }, + { + "description": "An array of names or relative paths to env files which will be loaded in the given order.", + "items": { + "description": "The name or relative path to an env file.", + "type": "string" + }, + "type": "array" + } + ] + } + } }, "executor_option": { - "additionalProperties": false, "description": "Configure the executor type for running tasks. Can be 'auto', 'poetry', 'virtualenv', or 'simple', with 'auto' being the default.", - "properties": { - "location": { - "description": "Specifies the location of the virtualenv relative to the parent directory. Relevant when 'type' is set to 'virtualenv'.", - "type": "string" + "oneOf": [ + { + "properties": { + "type": { + "$ref": "#/definitions/executor_option/definitions/type" + } + }, + "oneOf": [ + { + "properties": { + "extra": { + "description": "Include optional dependencies from the specified extra name.", + "oneOf": [ + { "type": "string" }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "group": { + "description": "Include dependencies from the specified dependency group.", + "oneOf": [ + { "type": "string" }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "no-group": { + "description": "Disable the specified dependency group.", + "oneOf": [ + { "type": "string" }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "with": { + "description": "Run with the given packages installed.", + "oneOf": [ + { "type": "string" }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "isolated": { + "description": "Run the command in an isolated virtual environment.", + "type": "boolean" + }, + "no-sync": { + "description": "Avoid syncing the virtual environment.", + "type": "boolean" + }, + "locked": { + "description": "Run without updating the uv.lock file.", + "type": "boolean" + }, + "frozen": { + "description": "Run without updating the uv.lock file.", + "type": "boolean" + }, + "no-project": { + "description": "Avoid discovering the project or workspace.", + "type": "boolean" + }, + "python": { + "description": "The Python interpreter to use for the run environment.", + "type": "string" + }, + "type": { + "const": "uv", + "type": "string" + } + } + }, + { + "properties": { + "location": { + "description": "Specifies the location of the virtualenv relative to the parent directory. Relevant when 'type' is set to 'virtualenv'.", + "type": "string" + }, + "type": { + "const": "virtualenv", + "type": "string" + } + } + }, + {} + ], + "required": ["type"], + "type": "object" }, + { + "$ref": "#/definitions/executor_option/definitions/type" + } + ], + "definitions": { "type": { "default": "auto", "description": "Specifies the executor type. 'auto' uses the most appropriate executor, 'poetry' uses the poetry environment, 'uv' uses `uv run` to run tasks, 'virtualenv' specifies a virtual environment, and 'simple' runs tasks without any specific environment setup.", "enum": ["auto", "poetry", "uv", "virtualenv", "simple"], "type": "string" } - }, - "type": "object" + } }, "cmd_task": { "allOf": [ @@ -234,6 +389,9 @@ "description": "Determines how to handle glob patterns with no matches. The default is 'pass', which causes unmatched patterns to be passed through to the command (just like in bash). Setting it to 'null' will replace an unmatched pattern with nothing, and setting it to 'fail' will cause the task to fail with an error if there are no matches.", "enum": ["pass", "null", "fail"] }, + "ignore_fail": { + "$ref": "#/definitions/ignore_fail_exec_option" + }, "cmd": { "title": "Command to execute", "description": "Executes a single command as a subprocess without a shell. Supports glob patterns for file matching, parameter expansion, and pattern matching. Environment variable templating is also supported within the command.", @@ -273,6 +431,9 @@ "description": "A Python expression to be evaluated. Can include environment variables and arguments.", "type": "string" }, + "ignore_fail": { + "$ref": "#/definitions/ignore_fail_exec_option" + }, "imports": { "description": "A list of Python modules to be imported for use in the expression.", "items": { @@ -296,11 +457,28 @@ { "type": "object", "properties": { + "ignore_fail": { + "description": "If true the failure of the referenced task will be ignored and the ref task will return exit code 0.", + "examples": [true], + "oneOf": [ + { + "type": "boolean" + } + ] + }, "ref": { "description": "A reference to another task by name, with optional additional arguments appended.", "type": "string" } }, + "not": { + "properties": { + "executor": { + "not": false + } + }, + "required": ["executor"] + }, "required": ["ref"] } ] @@ -319,6 +497,9 @@ { "type": "object", "properties": { + "ignore_fail": { + "$ref": "#/definitions/ignore_fail_exec_option" + }, "print_result": { "default": false, "description": "If true then the return value of the Python callable will be output to stdout, unless it is None.", @@ -352,16 +533,7 @@ "type": "string" }, "ignore_fail": { - "description": "If set, the sequence will continue running even if one of the tasks fails.", - "oneOf": [ - { - "type": "boolean" - }, - { - "enum": ["return_zero", "return_non_zero"], - "type": "string" - } - ] + "$ref": "#/definitions/ignore_fail_tasks_option" }, "sequence": { "$ref": "#/definitions/tasks_array", @@ -386,16 +558,7 @@ "type": "string" }, "ignore_fail": { - "description": "If true then the failure (or non-zero return value) of one task in the parallel group does not abort the execution.", - "oneOf": [ - { - "type": "boolean" - }, - { - "enum": ["return_zero", "return_non_zero"], - "type": "string" - } - ] + "$ref": "#/definitions/ignore_fail_tasks_option" }, "prefix": { "default": "{name}", @@ -432,6 +595,9 @@ { "type": "object", "properties": { + "ignore_fail": { + "$ref": "#/definitions/ignore_fail_exec_option" + }, "interpreter": { "description": "Specify the shell interpreter that this task should execute with, or a list of interpreters in order of preference.", "examples": [ From df7f8a829f8ed5a10872f74bf2faabfbdea8dc8b Mon Sep 17 00:00:00 2001 From: jcbustosp Date: Tue, 6 Jan 2026 18:34:06 +0100 Subject: [PATCH 5/6] Add rule group query_offset to Prometheus Schema (#5265) * Add rule group query_offset to Prometheus Schema * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Juan BUSTOS Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/schemas/json/prometheus.rules.json | 4 ++++ src/test/prometheus.rules/rules.json | 1 + 2 files changed, 5 insertions(+) diff --git a/src/schemas/json/prometheus.rules.json b/src/schemas/json/prometheus.rules.json index 9e9d9446f08..7db9dc96bc5 100644 --- a/src/schemas/json/prometheus.rules.json +++ b/src/schemas/json/prometheus.rules.json @@ -103,6 +103,10 @@ "$ref": "#/definitions/duration", "description": "How often rules in the group are evaluated." }, + "query_offset": { + "$ref": "#/definitions/duration", + "description": "Offset the rule evaluation timestamp of this particular group by the specified duration into the past." + }, "labels": { "$ref": "#/definitions/labels", "description": "Labels to add or overwrite before storing the result for its rules. Labels defined in will override the key if it has a collision." diff --git a/src/test/prometheus.rules/rules.json b/src/test/prometheus.rules/rules.json index 4a251407914..33618bbaa4f 100644 --- a/src/test/prometheus.rules/rules.json +++ b/src/test/prometheus.rules/rules.json @@ -5,6 +5,7 @@ "severity": "critical" }, "name": "my-group-name", + "query_offset": "0s", "rules": [ { "alert": "InstanceDown", From 5b60a143806ba9e718a5de3860cfc980e233ec07 Mon Sep 17 00:00:00 2001 From: Jeong Min Oh Date: Wed, 7 Jan 2026 03:34:22 +0900 Subject: [PATCH 6/6] Add vespertide (#5262) * Add vespertide * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update catalog.json --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/api/json/catalog.json | 26 + src/schema-validation.jsonc | 6 + src/schemas/json/vespertide-migration.json | 716 ++++++++++++++++++ src/schemas/json/vespertide-model.json | 476 ++++++++++++ src/schemas/json/vespertide.json | 86 +++ .../vespertide-migration.json | 306 ++++++++ .../vespertide-model/vespertide-model.json | 47 ++ src/test/vespertide/vespertide.json | 6 + 8 files changed, 1669 insertions(+) create mode 100644 src/schemas/json/vespertide-migration.json create mode 100644 src/schemas/json/vespertide-model.json create mode 100644 src/schemas/json/vespertide.json create mode 100644 src/test/vespertide-migration/vespertide-migration.json create mode 100644 src/test/vespertide-model/vespertide-model.json create mode 100644 src/test/vespertide/vespertide.json diff --git a/src/api/json/catalog.json b/src/api/json/catalog.json index 8fb68dd6117..12976ac3873 100644 --- a/src/api/json/catalog.json +++ b/src/api/json/catalog.json @@ -9129,6 +9129,32 @@ "description": "JSX Zero-Runtime UI Styling Library", "fileMatch": ["devup.json"], "url": "https://www.schemastore.org/devup.json" + }, + { + "name": "Vespertide", + "description": "Vespertide configuration", + "fileMatch": ["**/vespertide.json"], + "url": "https://www.schemastore.org/vespertide.json" + }, + { + "name": "Vespertide Migration", + "description": "Vespertide migration file", + "fileMatch": [ + "**/migrations/**/*.vespertide.json", + "**/migrations/**/*.vespertide.yaml", + "**/migrations/**/*.vespertide.yml" + ], + "url": "https://www.schemastore.org/vespertide-migration.json" + }, + { + "name": "Vespertide Model", + "description": "Vespertide model file", + "fileMatch": [ + "**/models/**/*.vespertide.json", + "**/models/**/*.vespertide.yaml", + "**/models/**/*.vespertide.yml" + ], + "url": "https://www.schemastore.org/vespertide-model.json" } ] } diff --git a/src/schema-validation.jsonc b/src/schema-validation.jsonc index 31eb5b2d9c4..9a10f93baac 100644 --- a/src/schema-validation.jsonc +++ b/src/schema-validation.jsonc @@ -1342,6 +1342,12 @@ "logout-rules", "local-file" ] + }, + "vespertide-migration.json": { + "unknownFormat": ["uint32", "int64", "double", "int32"] + }, + "vespertide-model.json": { + "unknownFormat": ["uint32", "int64", "double", "int32"] } } } diff --git a/src/schemas/json/vespertide-migration.json b/src/schemas/json/vespertide-migration.json new file mode 100644 index 00000000000..9b2da433a6d --- /dev/null +++ b/src/schemas/json/vespertide-migration.json @@ -0,0 +1,716 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://www.schemastore.org/vespertide-migration.json", + "$defs": { + "ColumnDef": { + "type": "object", + "properties": { + "comment": { + "type": ["string", "null"] + }, + "default": { + "anyOf": [ + { + "$ref": "#/$defs/DefaultValue" + }, + { + "type": "null" + } + ] + }, + "foreign_key": { + "anyOf": [ + { + "$ref": "#/$defs/ForeignKeySyntax" + }, + { + "type": "null" + } + ] + }, + "index": { + "anyOf": [ + { + "$ref": "#/$defs/StrOrBoolOrArray" + }, + { + "type": "null" + } + ] + }, + "name": { + "type": "string" + }, + "nullable": { + "type": "boolean" + }, + "primary_key": { + "anyOf": [ + { + "$ref": "#/$defs/PrimaryKeySyntax" + }, + { + "type": "null" + } + ] + }, + "type": { + "$ref": "#/$defs/ColumnType" + }, + "unique": { + "anyOf": [ + { + "$ref": "#/$defs/StrOrBoolOrArray" + }, + { + "type": "null" + } + ] + } + }, + "required": ["name", "type", "nullable"] + }, + "ColumnType": { + "anyOf": [ + { + "$ref": "#/$defs/SimpleColumnType" + }, + { + "$ref": "#/$defs/ComplexColumnType" + } + ] + }, + "ComplexColumnType": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "varchar" + }, + "length": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": ["kind", "length"] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "numeric" + }, + "precision": { + "type": "integer", + "format": "uint32", + "minimum": 0 + }, + "scale": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": ["kind", "precision", "scale"] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "char" + }, + "length": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": ["kind", "length"] + }, + { + "type": "object", + "properties": { + "custom_type": { + "type": "string" + }, + "kind": { + "type": "string", + "const": "custom" + } + }, + "required": ["kind", "custom_type"] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "enum" + }, + "name": { + "type": "string" + }, + "values": { + "$ref": "#/$defs/EnumValues" + } + }, + "required": ["kind", "name", "values"] + } + ] + }, + "DefaultValue": { + "description": "A value that can be a string, boolean, or number.\nThis is used for default values where columns can use literal values directly.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "number", + "format": "double" + }, + { + "type": "string" + } + ] + }, + "EnumValues": { + "description": "Enum values definition - either all string or all integer", + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/NumValue" + } + } + ] + }, + "ForeignKeyDef": { + "type": "object", + "properties": { + "on_delete": { + "anyOf": [ + { + "$ref": "#/$defs/ReferenceAction" + }, + { + "type": "null" + } + ] + }, + "on_update": { + "anyOf": [ + { + "$ref": "#/$defs/ReferenceAction" + }, + { + "type": "null" + } + ] + }, + "ref_columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "ref_table": { + "type": "string" + } + }, + "required": ["ref_table", "ref_columns"] + }, + "ForeignKeySyntax": { + "anyOf": [ + { + "description": "table.column", + "type": "string" + }, + { + "$ref": "#/$defs/ForeignKeyDef" + } + ] + }, + "MigrationAction": { + "oneOf": [ + { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "$ref": "#/$defs/ColumnDef" + } + }, + "constraints": { + "type": "array", + "items": { + "$ref": "#/$defs/TableConstraint" + } + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "create_table" + } + }, + "required": ["type", "table", "columns", "constraints"] + }, + { + "type": "object", + "properties": { + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "delete_table" + } + }, + "required": ["type", "table"] + }, + { + "type": "object", + "properties": { + "column": { + "$ref": "#/$defs/ColumnDef" + }, + "fill_with": { + "description": "Optional fill value to backfill existing rows when adding NOT NULL without default.", + "type": ["string", "null"] + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "add_column" + } + }, + "required": ["type", "table", "column"] + }, + { + "type": "object", + "properties": { + "from": { + "type": "string" + }, + "table": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "type": "string", + "const": "rename_column" + } + }, + "required": ["type", "table", "from", "to"] + }, + { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "delete_column" + } + }, + "required": ["type", "table", "column"] + }, + { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "new_type": { + "$ref": "#/$defs/ColumnType" + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "modify_column_type" + } + }, + "required": ["type", "table", "column", "new_type"] + }, + { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "fill_with": { + "description": "Required when changing from nullable to non-nullable to backfill existing NULL values.", + "type": ["string", "null"] + }, + "nullable": { + "type": "boolean" + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "modify_column_nullable" + } + }, + "required": ["type", "table", "column", "nullable"] + }, + { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "new_default": { + "description": "The new default value, or None to remove the default.", + "type": ["string", "null"] + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "modify_column_default" + } + }, + "required": ["type", "table", "column"] + }, + { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "new_comment": { + "description": "The new comment, or None to remove the comment.", + "type": ["string", "null"] + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "modify_column_comment" + } + }, + "required": ["type", "table", "column"] + }, + { + "type": "object", + "properties": { + "constraint": { + "$ref": "#/$defs/TableConstraint" + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "add_constraint" + } + }, + "required": ["type", "table", "constraint"] + }, + { + "type": "object", + "properties": { + "constraint": { + "$ref": "#/$defs/TableConstraint" + }, + "table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "remove_constraint" + } + }, + "required": ["type", "table", "constraint"] + }, + { + "type": "object", + "properties": { + "from": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "type": "string", + "const": "rename_table" + } + }, + "required": ["type", "from", "to"] + }, + { + "type": "object", + "properties": { + "sql": { + "type": "string" + }, + "type": { + "type": "string", + "const": "raw_sql" + } + }, + "required": ["type", "sql"] + } + ] + }, + "NumValue": { + "description": "Integer enum variant with name and numeric value", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "integer", + "format": "int32" + } + }, + "required": ["name", "value"] + }, + "PrimaryKeyDef": { + "type": "object", + "properties": { + "auto_increment": { + "type": "boolean", + "default": false + } + } + }, + "PrimaryKeySyntax": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/$defs/PrimaryKeyDef" + } + ] + }, + "ReferenceAction": { + "type": "string", + "enum": ["cascade", "restrict", "set_null", "set_default", "no_action"] + }, + "SimpleColumnType": { + "type": "string", + "enum": [ + "small_int", + "integer", + "big_int", + "real", + "double_precision", + "text", + "boolean", + "date", + "time", + "timestamp", + "timestamptz", + "interval", + "bytea", + "uuid", + "json", + "jsonb", + "inet", + "cidr", + "macaddr", + "xml" + ] + }, + "StrOrBoolOrArray": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "boolean" + } + ] + }, + "TableConstraint": { + "oneOf": [ + { + "type": "object", + "properties": { + "auto_increment": { + "type": "boolean", + "default": false + }, + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "type": { + "type": "string", + "const": "primary_key" + } + }, + "required": ["type", "columns"] + }, + { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": ["string", "null"] + }, + "type": { + "type": "string", + "const": "unique" + } + }, + "required": ["type", "columns"] + }, + { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": ["string", "null"] + }, + "on_delete": { + "anyOf": [ + { + "$ref": "#/$defs/ReferenceAction" + }, + { + "type": "null" + } + ] + }, + "on_update": { + "anyOf": [ + { + "$ref": "#/$defs/ReferenceAction" + }, + { + "type": "null" + } + ] + }, + "ref_columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "ref_table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "foreign_key" + } + }, + "required": ["type", "columns", "ref_table", "ref_columns"] + }, + { + "type": "object", + "properties": { + "expr": { + "type": "string" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string", + "const": "check" + } + }, + "required": ["type", "name", "expr"] + }, + { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": ["string", "null"] + }, + "type": { + "type": "string", + "const": "index" + } + }, + "required": ["type", "columns"] + } + ] + } + }, + "title": "MigrationPlan", + "type": "object", + "properties": { + "actions": { + "type": "array", + "items": { + "$ref": "#/$defs/MigrationAction" + } + }, + "comment": { + "type": ["string", "null"] + }, + "created_at": { + "type": ["string", "null"], + "default": null + }, + "version": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": ["version", "actions"] +} diff --git a/src/schemas/json/vespertide-model.json b/src/schemas/json/vespertide-model.json new file mode 100644 index 00000000000..732621a76c5 --- /dev/null +++ b/src/schemas/json/vespertide-model.json @@ -0,0 +1,476 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://www.schemastore.org/vespertide-model.json", + "$defs": { + "ColumnDef": { + "type": "object", + "properties": { + "comment": { + "type": ["string", "null"] + }, + "default": { + "anyOf": [ + { + "$ref": "#/$defs/DefaultValue" + }, + { + "type": "null" + } + ] + }, + "foreign_key": { + "anyOf": [ + { + "$ref": "#/$defs/ForeignKeySyntax" + }, + { + "type": "null" + } + ] + }, + "index": { + "anyOf": [ + { + "$ref": "#/$defs/StrOrBoolOrArray" + }, + { + "type": "null" + } + ] + }, + "name": { + "type": "string" + }, + "nullable": { + "type": "boolean" + }, + "primary_key": { + "anyOf": [ + { + "$ref": "#/$defs/PrimaryKeySyntax" + }, + { + "type": "null" + } + ] + }, + "type": { + "$ref": "#/$defs/ColumnType" + }, + "unique": { + "anyOf": [ + { + "$ref": "#/$defs/StrOrBoolOrArray" + }, + { + "type": "null" + } + ] + } + }, + "required": ["name", "type", "nullable"] + }, + "ColumnType": { + "anyOf": [ + { + "$ref": "#/$defs/SimpleColumnType" + }, + { + "$ref": "#/$defs/ComplexColumnType" + } + ] + }, + "ComplexColumnType": { + "oneOf": [ + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "varchar" + }, + "length": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": ["kind", "length"] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "numeric" + }, + "precision": { + "type": "integer", + "format": "uint32", + "minimum": 0 + }, + "scale": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": ["kind", "precision", "scale"] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "char" + }, + "length": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": ["kind", "length"] + }, + { + "type": "object", + "properties": { + "custom_type": { + "type": "string" + }, + "kind": { + "type": "string", + "const": "custom" + } + }, + "required": ["kind", "custom_type"] + }, + { + "type": "object", + "properties": { + "kind": { + "type": "string", + "const": "enum" + }, + "name": { + "type": "string" + }, + "values": { + "$ref": "#/$defs/EnumValues" + } + }, + "required": ["kind", "name", "values"] + } + ] + }, + "DefaultValue": { + "description": "A value that can be a string, boolean, or number.\nThis is used for default values where columns can use literal values directly.", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "number", + "format": "double" + }, + { + "type": "string" + } + ] + }, + "EnumValues": { + "description": "Enum values definition - either all string or all integer", + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/NumValue" + } + } + ] + }, + "ForeignKeyDef": { + "type": "object", + "properties": { + "on_delete": { + "anyOf": [ + { + "$ref": "#/$defs/ReferenceAction" + }, + { + "type": "null" + } + ] + }, + "on_update": { + "anyOf": [ + { + "$ref": "#/$defs/ReferenceAction" + }, + { + "type": "null" + } + ] + }, + "ref_columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "ref_table": { + "type": "string" + } + }, + "required": ["ref_table", "ref_columns"] + }, + "ForeignKeySyntax": { + "anyOf": [ + { + "description": "table.column", + "type": "string" + }, + { + "$ref": "#/$defs/ForeignKeyDef" + } + ] + }, + "NumValue": { + "description": "Integer enum variant with name and numeric value", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "integer", + "format": "int32" + } + }, + "required": ["name", "value"] + }, + "PrimaryKeyDef": { + "type": "object", + "properties": { + "auto_increment": { + "type": "boolean", + "default": false + } + } + }, + "PrimaryKeySyntax": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/$defs/PrimaryKeyDef" + } + ] + }, + "ReferenceAction": { + "type": "string", + "enum": ["cascade", "restrict", "set_null", "set_default", "no_action"] + }, + "SimpleColumnType": { + "type": "string", + "enum": [ + "small_int", + "integer", + "big_int", + "real", + "double_precision", + "text", + "boolean", + "date", + "time", + "timestamp", + "timestamptz", + "interval", + "bytea", + "uuid", + "json", + "jsonb", + "inet", + "cidr", + "macaddr", + "xml" + ] + }, + "StrOrBoolOrArray": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "boolean" + } + ] + }, + "TableConstraint": { + "oneOf": [ + { + "type": "object", + "properties": { + "auto_increment": { + "type": "boolean", + "default": false + }, + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "type": { + "type": "string", + "const": "primary_key" + } + }, + "required": ["type", "columns"] + }, + { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": ["string", "null"] + }, + "type": { + "type": "string", + "const": "unique" + } + }, + "required": ["type", "columns"] + }, + { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": ["string", "null"] + }, + "on_delete": { + "anyOf": [ + { + "$ref": "#/$defs/ReferenceAction" + }, + { + "type": "null" + } + ] + }, + "on_update": { + "anyOf": [ + { + "$ref": "#/$defs/ReferenceAction" + }, + { + "type": "null" + } + ] + }, + "ref_columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "ref_table": { + "type": "string" + }, + "type": { + "type": "string", + "const": "foreign_key" + } + }, + "required": ["type", "columns", "ref_table", "ref_columns"] + }, + { + "type": "object", + "properties": { + "expr": { + "type": "string" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string", + "const": "check" + } + }, + "required": ["type", "name", "expr"] + }, + { + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": ["string", "null"] + }, + "type": { + "type": "string", + "const": "index" + } + }, + "required": ["type", "columns"] + } + ] + } + }, + "title": "TableDef", + "type": "object", + "properties": { + "columns": { + "type": "array", + "items": { + "$ref": "#/$defs/ColumnDef" + } + }, + "constraints": { + "type": "array", + "items": { + "$ref": "#/$defs/TableConstraint" + } + }, + "description": { + "type": ["string", "null"] + }, + "name": { + "type": "string" + } + }, + "required": ["name", "columns", "constraints"] +} diff --git a/src/schemas/json/vespertide.json b/src/schemas/json/vespertide.json new file mode 100644 index 00000000000..7d1255f74d3 --- /dev/null +++ b/src/schemas/json/vespertide.json @@ -0,0 +1,86 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://www.schemastore.org/vespertide.json", + "$defs": { + "FileFormat": { + "description": "Supported file formats for generated artifacts.", + "type": "string", + "enum": ["json", "yaml", "yml"] + }, + "NameCase": { + "description": "Supported naming cases.", + "type": "string", + "enum": ["snake", "camel", "pascal"] + }, + "SeaOrmConfig": { + "description": "SeaORM-specific export configuration.", + "type": "object", + "properties": { + "extraEnumDerives": { + "description": "Additional derive macros to add to generated enum types.\nDefault: `[\"vespera::Schema\"]`", + "type": "array", + "default": ["vespera::Schema"], + "items": { + "type": "string" + } + }, + "extraModelDerives": { + "description": "Additional derive macros to add to generated entity model types.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + } + } + } + }, + "title": "VespertideConfig", + "description": "Top-level vespertide configuration.", + "type": "object", + "properties": { + "columnNamingCase": { + "$ref": "#/$defs/NameCase" + }, + "migrationFilenamePattern": { + "type": "string", + "default": "%04v_%m" + }, + "migrationFormat": { + "$ref": "#/$defs/FileFormat", + "default": "json" + }, + "migrationsDir": { + "type": "string" + }, + "modelExportDir": { + "description": "Output directory for generated ORM models.", + "type": "string", + "default": "src/models" + }, + "modelFormat": { + "$ref": "#/$defs/FileFormat", + "default": "json" + }, + "modelsDir": { + "type": "string" + }, + "seaorm": { + "$ref": "#/$defs/SeaOrmConfig", + "description": "SeaORM-specific export configuration.", + "default": { + "extraEnumDerives": ["vespera::Schema"], + "extraModelDerives": [] + } + }, + "tableNamingCase": { + "$ref": "#/$defs/NameCase" + } + }, + "required": [ + "modelsDir", + "migrationsDir", + "tableNamingCase", + "columnNamingCase" + ] +} diff --git a/src/test/vespertide-migration/vespertide-migration.json b/src/test/vespertide-migration/vespertide-migration.json new file mode 100644 index 00000000000..afb56cf2b8a --- /dev/null +++ b/src/test/vespertide-migration/vespertide-migration.json @@ -0,0 +1,306 @@ +{ + "actions": [ + { + "columns": [ + { + "default": "gen_random_uuid()", + "name": "id", + "nullable": false, + "primary_key": true, + "type": "uuid" + }, + { + "index": true, + "name": "email", + "nullable": false, + "type": { + "kind": "varchar", + "length": 255 + }, + "unique": true + }, + { + "name": "password", + "nullable": false, + "type": { + "kind": "varchar", + "length": 255 + } + }, + { + "name": "name", + "nullable": false, + "type": { + "kind": "varchar", + "length": 100 + } + }, + { + "name": "profile_image", + "nullable": true, + "type": "text" + }, + { + "default": "now()", + "name": "created_at", + "nullable": false, + "type": "timestamptz" + }, + { + "name": "updated_at", + "nullable": true, + "type": "timestamptz" + } + ], + "constraints": [], + "table": "user", + "type": "create_table" + }, + { + "columns": [ + { + "default": "gen_random_uuid()", + "name": "id", + "nullable": false, + "primary_key": true, + "type": "uuid" + }, + { + "name": "name", + "nullable": false, + "type": { + "kind": "varchar", + "length": 100 + } + }, + { + "name": "description", + "nullable": true, + "type": "text" + }, + { + "name": "logo", + "nullable": true, + "type": "text" + }, + { + "foreign_key": { + "on_delete": "cascade", + "on_update": null, + "ref_columns": ["id"], + "ref_table": "user" + }, + "index": true, + "name": "owner_id", + "nullable": false, + "type": "uuid" + }, + { + "default": "now()", + "name": "created_at", + "nullable": false, + "type": "timestamptz" + }, + { + "name": "updated_at", + "nullable": true, + "type": "timestamptz" + } + ], + "constraints": [], + "table": "media", + "type": "create_table" + }, + { + "columns": [ + { + "foreign_key": { + "on_delete": "cascade", + "on_update": null, + "ref_columns": ["id"], + "ref_table": "media" + }, + "name": "media_id", + "nullable": false, + "primary_key": true, + "type": "uuid" + }, + { + "name": "id", + "nullable": false, + "primary_key": true, + "type": "big_int" + }, + { + "name": "title", + "nullable": false, + "type": { + "kind": "varchar", + "length": 500 + } + }, + { + "name": "content", + "nullable": false, + "type": "text" + }, + { + "name": "summary", + "nullable": true, + "type": "text" + }, + { + "name": "thumbnail", + "nullable": true, + "type": "text" + }, + { + "default": "'draft'", + "index": true, + "name": "status", + "nullable": false, + "type": { + "kind": "enum", + "name": "article_status", + "values": ["draft", "review", "published", "archived"] + } + }, + { + "index": true, + "name": "published_at", + "nullable": true, + "type": "timestamptz" + }, + { + "default": "now()", + "name": "created_at", + "nullable": false, + "type": "timestamptz" + }, + { + "name": "updated_at", + "nullable": true, + "type": "timestamptz" + } + ], + "constraints": [], + "table": "article", + "type": "create_table" + }, + { + "columns": [ + { + "foreign_key": { + "on_delete": "cascade", + "on_update": null, + "ref_columns": ["id"], + "ref_table": "user" + }, + "index": true, + "name": "user_id", + "nullable": false, + "primary_key": true, + "type": "uuid" + }, + { + "foreign_key": { + "on_delete": "cascade", + "on_update": null, + "ref_columns": ["id"], + "ref_table": "media" + }, + "index": true, + "name": "media_id", + "nullable": false, + "primary_key": true, + "type": "uuid" + }, + { + "index": true, + "name": "role", + "nullable": false, + "type": { + "kind": "enum", + "name": "media_role", + "values": ["owner", "editor", "reporter"] + } + }, + { + "default": "now()", + "name": "created_at", + "nullable": false, + "type": "timestamptz" + } + ], + "constraints": [], + "table": "user_media_role", + "type": "create_table" + }, + { + "columns": [ + { + "name": "media_id", + "nullable": false, + "primary_key": true, + "type": "uuid" + }, + { + "name": "article_id", + "nullable": false, + "primary_key": true, + "type": "big_int" + }, + { + "foreign_key": { + "on_delete": "cascade", + "on_update": null, + "ref_columns": ["id"], + "ref_table": "user" + }, + "index": true, + "name": "user_id", + "nullable": false, + "primary_key": true, + "type": "uuid" + }, + { + "default": "1", + "name": "author_order", + "nullable": false, + "type": "integer" + }, + { + "default": "'contributor'", + "name": "role", + "nullable": false, + "type": { + "kind": "enum", + "name": "article_user_role", + "values": ["lead", "contributor"] + } + }, + { + "default": "now()", + "name": "created_at", + "nullable": false, + "type": "timestamptz" + } + ], + "constraints": [ + { + "columns": ["media_id", "article_id"], + "on_delete": "cascade", + "on_update": null, + "ref_columns": ["media_id", "id"], + "ref_table": "article", + "type": "foreign_key" + } + ], + "table": "article_user", + "type": "create_table" + } + ], + "comment": "Init", + "created_at": "2025-12-19T08:38:59Z", + "version": 1 +} diff --git a/src/test/vespertide-model/vespertide-model.json b/src/test/vespertide-model/vespertide-model.json new file mode 100644 index 00000000000..d3ad7f801ba --- /dev/null +++ b/src/test/vespertide-model/vespertide-model.json @@ -0,0 +1,47 @@ +{ + "columns": [ + { + "default": "gen_random_uuid()", + "name": "id", + "nullable": false, + "primary_key": true, + "type": "uuid" + }, + { + "index": true, + "name": "email", + "nullable": false, + "type": { "kind": "varchar", "length": 255 }, + "unique": true + }, + { + "name": "password", + "nullable": false, + "type": { "kind": "varchar", "length": 255 } + }, + { + "name": "name", + "nullable": false, + "type": { "kind": "varchar", "length": 100 } + }, + { + "name": "profile_image", + "nullable": true, + "type": "text" + }, + { + "default": "now()", + "name": "created_at", + "nullable": false, + "type": "timestamptz" + }, + { + "name": "updated_at", + "nullable": true, + "type": "timestamptz" + } + ], + "constraints": [], + "indexes": [], + "name": "user" +} diff --git a/src/test/vespertide/vespertide.json b/src/test/vespertide/vespertide.json new file mode 100644 index 00000000000..165a50bb972 --- /dev/null +++ b/src/test/vespertide/vespertide.json @@ -0,0 +1,6 @@ +{ + "columnNamingCase": "snake", + "migrationsDir": "migrations", + "modelsDir": "models", + "tableNamingCase": "snake" +}