diff --git a/src/api/json/catalog.json b/src/api/json/catalog.json index 50e6e4624f5..ad731498fc4 100644 --- a/src/api/json/catalog.json +++ b/src/api/json/catalog.json @@ -980,6 +980,12 @@ "fileMatch": [".backportrc.json"], "url": "https://www.schemastore.org/backportrc.json" }, + { + "name": "basedpyright", + "description": "Basedpyright configuration file", + "fileMatch": ["basedpyrightconfig.json"], + "url": "https://raw.githubusercontent.com/DetachHead/basedpyright/refs/heads/main/packages/vscode-pyright/schemas/pyrightconfig.schema.json" + }, { "name": "batect.yml", "description": "Batect configuration file", @@ -5030,6 +5036,12 @@ "fileMatch": ["prefect.yaml", "prefect.yml"], "url": "https://raw.githubusercontent.com/PrefectHQ/prefect/refs/heads/main/schemas/prefect.yaml.schema.json" }, + { + "name": "prek", + "description": "Configuration file for prek, a tool for managing git hooks", + "fileMatch": ["prek.toml"], + "url": "https://www.schemastore.org/prek.json" + }, { "name": "prettierrc.json", "description": ".prettierrc configuration file", @@ -8404,7 +8416,7 @@ "vcluster.yaml", "vcluster.yml" ], - "url": "https://raw.githubusercontent.com/loft-sh/vcluster-config/main/vcluster.schema.json" + "url": "https://raw.githubusercontent.com/loft-sh/vcluster/main/chart/values.schema.json" }, { "name": "well-known-fursona", diff --git a/src/negative_test/claude-code-settings/invalid-enum-values.json b/src/negative_test/claude-code-settings/invalid-enum-values.json index 250d2b2b679..974395f2785 100644 --- a/src/negative_test/claude-code-settings/invalid-enum-values.json +++ b/src/negative_test/claude-code-settings/invalid-enum-values.json @@ -2,5 +2,9 @@ "forceLoginMethod": "github", "permissions": { "defaultMode": "invalid-mode" + }, + "spinnerVerbs": { + "mode": "merge", + "verbs": ["Analyzing"] } } diff --git a/src/negative_test/claude-code-settings/invalid-marketplace-host-pattern.json b/src/negative_test/claude-code-settings/invalid-marketplace-host-pattern.json new file mode 100644 index 00000000000..feb9ce9d9f5 --- /dev/null +++ b/src/negative_test/claude-code-settings/invalid-marketplace-host-pattern.json @@ -0,0 +1,15 @@ +{ + "extraKnownMarketplaces": { + "internal-git": { + "source": { + "source": "hostPattern" + } + } + }, + "strictKnownMarketplaces": [ + { + "hostPattern": 123, + "source": "hostPattern" + } + ] +} diff --git a/src/negative_test/claude-code-settings/wrong-property-types.json b/src/negative_test/claude-code-settings/wrong-property-types.json index d199f2a58a4..3a8f687c9da 100644 --- a/src/negative_test/claude-code-settings/wrong-property-types.json +++ b/src/negative_test/claude-code-settings/wrong-property-types.json @@ -1,10 +1,29 @@ { "cleanupPeriodDays": "thirty", "enableAllProjectMcpServers": 1, + "hooks": { + "PreToolUse": [ + { + "hooks": [ + { + "async": "true", + "command": "echo test", + "type": "command" + } + ] + } + ] + }, "includeCoAuthoredBy": "yes", "permissions": { "additionalDirectories": "should be array", "allow": "should be array", "ask": "should be array" + }, + "sandbox": { + "network": { + "allowAllUnixSockets": "yes", + "allowedDomains": "api.anthropic.com" + } } } diff --git a/src/schemas/json/claude-code-settings.json b/src/schemas/json/claude-code-settings.json index 9957f96e8a8..7bbec15a43e 100644 --- a/src/schemas/json/claude-code-settings.json +++ b/src/schemas/json/claude-code-settings.json @@ -5,7 +5,7 @@ "permissionRule": { "type": "string", "description": "Tool permission rule. See https://code.claude.com/docs/en/settings#permission-rule-syntax", - "pattern": "^((Bash|Edit|ExitPlanMode|Glob|Grep|KillShell|NotebookEdit|Read|Skill|Task|TodoWrite|WebFetch|WebSearch|Write)(\\((?=.*[^)*?])[^)]+\\))?|mcp__.*)$", + "pattern": "^((Bash|Edit|ExitPlanMode|Glob|Grep|KillShell|LS|MultiEdit|NotebookEdit|NotebookRead|Read|Skill|SlashCommand|Task|TodoWrite|WebFetch|WebSearch|Write)(\\((?=.*[^)*?])[^)]+\\))?|mcp__.*)$", "examples": [ "Bash", "Bash(npm run build)", @@ -14,11 +14,13 @@ "Bash(ls*)", "Bash(git * main)", "Edit", + "MultiEdit", "Edit(/src/**/*.ts)", "Read(./.env)", "Read(./secrets/**)", "Read(/Users/alice/secrets/**)", "Read(~/Documents/*.pdf)", + "SlashCommand(/clear)", "WebFetch", "WebFetch(domain:example.com)", "mcp__github__search_repositories" @@ -46,6 +48,10 @@ "type": "number", "description": "Optional timeout in seconds", "exclusiveMinimum": 0 + }, + "async": { + "type": "boolean", + "description": "Run this hook asynchronously without blocking Claude Code" } } }, @@ -69,6 +75,10 @@ "type": "number", "description": "Optional timeout in seconds", "exclusiveMinimum": 0 + }, + "async": { + "type": "boolean", + "description": "Run this hook asynchronously without blocking Claude Code" } } } @@ -517,6 +527,21 @@ "required": ["source", "url"], "additionalProperties": false }, + { + "type": "object", + "properties": { + "source": { + "type": "string", + "const": "hostPattern" + }, + "hostPattern": { + "type": "string", + "description": "Git host pattern to trust for repositories in source specifications" + } + }, + "required": ["source", "hostPattern"], + "additionalProperties": false + }, { "type": "object", "properties": { @@ -627,6 +652,21 @@ "description": "(Managed settings only) Allowlist of plugin marketplaces users can add. Undefined = no restrictions, empty array = lockdown. Uses exact matching for source specifications. See https://code.claude.com/docs/en/settings#strictknownmarketplaces", "items": { "anyOf": [ + { + "type": "object", + "properties": { + "source": { + "type": "string", + "const": "hostPattern" + }, + "hostPattern": { + "type": "string", + "description": "Git host pattern to trust for repositories in source specifications" + } + }, + "required": ["source", "hostPattern"], + "additionalProperties": false + }, { "type": "object", "properties": { @@ -822,6 +862,26 @@ "minimum": 1, "maximum": 65535, "description": "SOCKS proxy port to use for network filtering. If not specified, a proxy server will be started automatically" + }, + "allowAllUnixSockets": { + "type": "boolean", + "description": "Allow all Unix domain socket connections. If true, this overrides allowUnixSockets" + }, + "allowedDomains": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "description": "Allowlist of network domains for sandboxed commands. Supports wildcard patterns like *.example.com" + }, + "deniedDomains": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "description": "Denylist of network domains for sandboxed commands. Supports wildcard patterns like *.example.com" } }, "additionalProperties": false @@ -863,6 +923,28 @@ }, "additionalProperties": false }, + "spinnerVerbs": { + "type": "object", + "description": "Customize the verbs shown in spinner progress messages", + "properties": { + "mode": { + "type": "string", + "enum": ["append", "replace"], + "description": "How custom verbs should be combined with the default spinner verbs" + }, + "verbs": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1, + "description": "Custom verbs used in spinner progress text" + } + }, + "required": ["verbs"], + "additionalProperties": false + }, "spinnerTipsEnabled": { "type": "boolean", "description": "Show tips in the spinner while Claude is working. Set to false to disable tips (default: true)", diff --git a/src/schemas/json/prek.json b/src/schemas/json/prek.json new file mode 100644 index 00000000000..c4620d7508f --- /dev/null +++ b/src/schemas/json/prek.json @@ -0,0 +1,950 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://www.schemastore.org/prek.json", + "title": "prek configuration file format", + "type": "object", + "properties": { + "repos": { + "type": "array", + "items": { + "$ref": "#/definitions/Repo" + } + }, + "default_install_hook_types": { + "description": "A list of `--hook-types` which will be used by default when running `prek install`.\nDefault is `[pre-commit]`.", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/HookType" + } + }, + "default_language_version": { + "description": "A mapping from language to the default `language_version`.", + "type": ["object", "null"], + "properties": { + "bun": { + "type": "string" + }, + "conda": { + "type": "string" + }, + "coursier": { + "type": "string" + }, + "dart": { + "type": "string" + }, + "docker": { + "type": "string" + }, + "docker_image": { + "type": "string" + }, + "dotnet": { + "type": "string" + }, + "fail": { + "type": "string" + }, + "golang": { + "type": "string" + }, + "haskell": { + "type": "string" + }, + "julia": { + "type": "string" + }, + "lua": { + "type": "string" + }, + "node": { + "type": "string" + }, + "perl": { + "type": "string" + }, + "pygrep": { + "type": "string" + }, + "python": { + "type": "string" + }, + "r": { + "type": "string" + }, + "ruby": { + "type": "string" + }, + "rust": { + "type": "string" + }, + "script": { + "type": "string" + }, + "swift": { + "type": "string" + }, + "system": { + "type": "string" + } + }, + "additionalProperties": false + }, + "default_stages": { + "description": "A configuration-wide default for the stages property of hooks.\nDefault to all stages.", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Stage" + } + }, + "files": { + "description": "Global file include pattern.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "exclude": { + "description": "Global file exclude pattern.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "fail_fast": { + "description": "Set to true to have prek stop running hooks after the first failure.\nDefault is false.", + "type": ["boolean", "null"] + }, + "minimum_prek_version": { + "description": "The minimum version of prek required to run this configuration.", + "type": ["string", "null"], + "default": null + }, + "orphan": { + "description": "Set to true to isolate this project from parent configurations in workspace mode.\nWhen true, files in this project are \"consumed\" by this project and will not be processed\nby parent projects.\nWhen false (default), files in subprojects are processed by both the subproject and\nany parent projects that contain them.", + "type": ["boolean", "null"] + } + }, + "required": ["repos"], + "additionalProperties": true, + "definitions": { + "Repo": { + "description": "A repository of hooks, which can be remote, local, meta, or builtin.", + "type": "object", + "oneOf": [ + { + "$ref": "#/definitions/RemoteRepo" + }, + { + "$ref": "#/definitions/LocalRepo" + }, + { + "$ref": "#/definitions/MetaRepo" + }, + { + "$ref": "#/definitions/BuiltinRepo" + } + ] + }, + "RemoteRepo": { + "type": "object", + "properties": { + "repo": { + "description": "Remote repository location. Must not be `local`, `meta`, or `builtin`.", + "type": "string", + "not": { + "enum": ["local", "meta", "builtin"] + } + }, + "rev": { + "type": "string" + }, + "hooks": { + "type": "array", + "items": { + "$ref": "#/definitions/RemoteHook" + }, + "writeOnly": true + } + }, + "required": ["repo", "rev", "hooks"], + "additionalProperties": true + }, + "RemoteHook": { + "description": "A remote hook in the configuration file.\n\nAll keys in manifest hook dict are valid in a config hook dict, but are optional.", + "type": "object", + "properties": { + "id": { + "description": "The id of the hook.", + "type": "string" + }, + "name": { + "description": "Override the name of the hook.", + "type": ["string", "null"] + }, + "entry": { + "description": "Override the entrypoint. Not documented in the official docs but works.", + "type": ["string", "null"] + }, + "language": { + "description": "Override the language. Not documented in the official docs but works.", + "anyOf": [ + { + "$ref": "#/definitions/Language" + }, + { + "type": "null" + } + ] + }, + "priority": { + "description": "Priority used by the scheduler to determine ordering and concurrency.\nHooks with the same priority can run in parallel.\n\nThis is only allowed in project config files (e.g. `.pre-commit-config.yaml`).\nIt is not allowed in manifests (e.g. `.pre-commit-hooks.yaml`).", + "type": ["integer", "null"], + "minimum": 0 + }, + "alias": { + "description": "Not documented in the official docs.", + "type": ["string", "null"] + }, + "files": { + "description": "The pattern of files to run on.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "exclude": { + "description": "Exclude files that were matched by `files`.\nDefault is `$^`, which matches nothing.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "types": { + "description": "List of file types to run on (AND).\nDefault is `[file]`, which matches all files.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "types_or": { + "description": "List of file types to run on (OR).\nDefault is `[]`.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "exclude_types": { + "description": "List of file types to exclude.\nDefault is `[]`.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "additional_dependencies": { + "description": "Not documented in the official docs.", + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "args": { + "description": "Additional arguments to pass to the hook.", + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "env": { + "description": "Environment variables to set for the hook.", + "type": ["object", "null"], + "additionalProperties": { + "type": "string" + } + }, + "always_run": { + "description": "This hook will run even if there are no matching files.\nDefault is false.", + "type": ["boolean", "null"] + }, + "fail_fast": { + "description": "If this hook fails, don't run any more hooks.\nDefault is false.", + "type": ["boolean", "null"] + }, + "pass_filenames": { + "description": "Append filenames that would be checked to the hook entry as arguments.\nDefault is true.", + "type": ["boolean", "null"] + }, + "description": { + "description": "A description of the hook. For metadata only.", + "type": ["string", "null"] + }, + "language_version": { + "description": "Run the hook on a specific version of the language.\nDefault is `default`.\nSee .", + "type": ["string", "null"] + }, + "log_file": { + "description": "Write the output of the hook to a file when the hook fails or verbose is enabled.", + "type": ["string", "null"] + }, + "require_serial": { + "description": "This hook will execute using a single process instead of in parallel.\nDefault is false.", + "type": ["boolean", "null"] + }, + "stages": { + "description": "Select which git hook(s) to run for.\nDefault all stages are selected.\nSee .", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Stage" + } + }, + "verbose": { + "description": "Print the output of the hook even if it passes.\nDefault is false.", + "type": ["boolean", "null"] + }, + "minimum_prek_version": { + "description": "The minimum version of prek required to run this hook.", + "type": ["string", "null"], + "default": null + } + }, + "required": ["id"], + "additionalProperties": true + }, + "Language": { + "type": "string", + "enum": [ + "bun", + "conda", + "coursier", + "dart", + "docker", + "docker_image", + "dotnet", + "fail", + "golang", + "haskell", + "julia", + "lua", + "node", + "perl", + "pygrep", + "python", + "r", + "ruby", + "rust", + "script", + "swift", + "system" + ] + }, + "FilePattern": { + "description": "A file pattern, either a regex or glob pattern(s).", + "oneOf": [ + { + "description": "A regular expression pattern.", + "type": "string" + }, + { + "type": "object", + "properties": { + "glob": { + "oneOf": [ + { + "description": "A glob pattern.", + "type": "string" + }, + { + "description": "A list of glob patterns.", + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": ["glob"] + } + ] + }, + "Stage": { + "type": "string", + "enum": [ + "manual", + "commit-msg", + "post-checkout", + "post-commit", + "post-merge", + "post-rewrite", + "pre-commit", + "pre-merge-commit", + "pre-push", + "pre-rebase", + "prepare-commit-msg" + ] + }, + "LocalRepo": { + "type": "object", + "properties": { + "repo": { + "description": "Must be `local`.", + "type": "string", + "const": "local" + }, + "hooks": { + "type": "array", + "items": { + "$ref": "#/definitions/LocalHook" + } + } + }, + "required": ["repo", "hooks"], + "additionalProperties": true + }, + "LocalHook": { + "description": "A local hook in the configuration file.\n\nThis is similar to `ManifestHook`, but includes config-only fields (like `priority`).", + "type": "object", + "properties": { + "id": { + "description": "The id of the hook.", + "type": "string" + }, + "name": { + "description": "The name of the hook.", + "type": "string" + }, + "entry": { + "description": "The command to run. It can contain arguments that will not be overridden.", + "type": "string" + }, + "language": { + "description": "The language of the hook. Tells prek how to install and run the hook.", + "allOf": [ + { + "$ref": "#/definitions/Language" + } + ] + }, + "priority": { + "description": "Priority used by the scheduler to determine ordering and concurrency.\nHooks with the same priority can run in parallel.", + "type": ["integer", "null"], + "minimum": 0 + }, + "alias": { + "description": "Not documented in the official docs.", + "type": ["string", "null"] + }, + "files": { + "description": "The pattern of files to run on.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "exclude": { + "description": "Exclude files that were matched by `files`.\nDefault is `$^`, which matches nothing.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "types": { + "description": "List of file types to run on (AND).\nDefault is `[file]`, which matches all files.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "types_or": { + "description": "List of file types to run on (OR).\nDefault is `[]`.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "exclude_types": { + "description": "List of file types to exclude.\nDefault is `[]`.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "additional_dependencies": { + "description": "Not documented in the official docs.", + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "args": { + "description": "Additional arguments to pass to the hook.", + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "env": { + "description": "Environment variables to set for the hook.", + "type": ["object", "null"], + "additionalProperties": { + "type": "string" + } + }, + "always_run": { + "description": "This hook will run even if there are no matching files.\nDefault is false.", + "type": ["boolean", "null"] + }, + "fail_fast": { + "description": "If this hook fails, don't run any more hooks.\nDefault is false.", + "type": ["boolean", "null"] + }, + "pass_filenames": { + "description": "Append filenames that would be checked to the hook entry as arguments.\nDefault is true.", + "type": ["boolean", "null"] + }, + "description": { + "description": "A description of the hook. For metadata only.", + "type": ["string", "null"] + }, + "language_version": { + "description": "Run the hook on a specific version of the language.\nDefault is `default`.\nSee .", + "type": ["string", "null"] + }, + "log_file": { + "description": "Write the output of the hook to a file when the hook fails or verbose is enabled.", + "type": ["string", "null"] + }, + "require_serial": { + "description": "This hook will execute using a single process instead of in parallel.\nDefault is false.", + "type": ["boolean", "null"] + }, + "stages": { + "description": "Select which git hook(s) to run for.\nDefault all stages are selected.\nSee .", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Stage" + } + }, + "verbose": { + "description": "Print the output of the hook even if it passes.\nDefault is false.", + "type": ["boolean", "null"] + }, + "minimum_prek_version": { + "description": "The minimum version of prek required to run this hook.", + "type": ["string", "null"], + "default": null + } + }, + "required": ["id", "name", "entry", "language"], + "additionalProperties": true + }, + "MetaRepo": { + "type": "object", + "properties": { + "repo": { + "description": "Must be `meta`.", + "type": "string", + "const": "meta" + }, + "hooks": { + "type": "array", + "items": { + "$ref": "#/definitions/MetaHook" + } + } + }, + "required": ["repo", "hooks"], + "additionalProperties": true + }, + "MetaHook": { + "description": "A meta hook predefined in prek.", + "type": "object", + "properties": { + "id": { + "$ref": "#/definitions/MetaHooks" + }, + "name": { + "description": "Override the name of the hook.", + "type": ["string", "null"] + }, + "entry": { + "description": "Entry is not allowed for predefined hooks.", + "const": false + }, + "language": { + "anyOf": [ + { + "description": "Language must be `system` for predefined hooks (or omitted).", + "type": "string", + "enum": ["system"] + }, + { + "type": "null" + } + ] + }, + "priority": { + "description": "Priority used by the scheduler to determine ordering and concurrency.\nHooks with the same priority can run in parallel.\n\nThis is only allowed in project config files (e.g. `.pre-commit-config.yaml`).\nIt is not allowed in manifests (e.g. `.pre-commit-hooks.yaml`).", + "type": ["integer", "null"], + "minimum": 0 + }, + "alias": { + "description": "Not documented in the official docs.", + "type": ["string", "null"] + }, + "files": { + "description": "The pattern of files to run on.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "exclude": { + "description": "Exclude files that were matched by `files`.\nDefault is `$^`, which matches nothing.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "types": { + "description": "List of file types to run on (AND).\nDefault is `[file]`, which matches all files.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "types_or": { + "description": "List of file types to run on (OR).\nDefault is `[]`.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "exclude_types": { + "description": "List of file types to exclude.\nDefault is `[]`.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "additional_dependencies": { + "description": "Not documented in the official docs.", + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "args": { + "description": "Additional arguments to pass to the hook.", + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "env": { + "description": "Environment variables to set for the hook.", + "type": ["object", "null"], + "additionalProperties": { + "type": "string" + } + }, + "always_run": { + "description": "This hook will run even if there are no matching files.\nDefault is false.", + "type": ["boolean", "null"] + }, + "fail_fast": { + "description": "If this hook fails, don't run any more hooks.\nDefault is false.", + "type": ["boolean", "null"] + }, + "pass_filenames": { + "description": "Append filenames that would be checked to the hook entry as arguments.\nDefault is true.", + "type": ["boolean", "null"] + }, + "description": { + "description": "A description of the hook. For metadata only.", + "type": ["string", "null"] + }, + "language_version": { + "description": "Run the hook on a specific version of the language.\nDefault is `default`.\nSee .", + "type": ["string", "null"] + }, + "log_file": { + "description": "Write the output of the hook to a file when the hook fails or verbose is enabled.", + "type": ["string", "null"] + }, + "require_serial": { + "description": "This hook will execute using a single process instead of in parallel.\nDefault is false.", + "type": ["boolean", "null"] + }, + "stages": { + "description": "Select which git hook(s) to run for.\nDefault all stages are selected.\nSee .", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Stage" + } + }, + "verbose": { + "description": "Print the output of the hook even if it passes.\nDefault is false.", + "type": ["boolean", "null"] + }, + "minimum_prek_version": { + "description": "The minimum version of prek required to run this hook.", + "type": ["string", "null"], + "default": null + } + }, + "required": ["id"], + "additionalProperties": true + }, + "MetaHooks": { + "type": "string", + "enum": ["check-hooks-apply", "check-useless-excludes", "identity"] + }, + "BuiltinRepo": { + "type": "object", + "properties": { + "repo": { + "description": "Must be `builtin`.", + "type": "string", + "const": "builtin" + }, + "hooks": { + "type": "array", + "items": { + "$ref": "#/definitions/BuiltinHook" + } + } + }, + "required": ["repo", "hooks"], + "additionalProperties": true + }, + "BuiltinHook": { + "description": "A builtin hook predefined in prek.", + "type": "object", + "properties": { + "id": { + "$ref": "#/definitions/BuiltinHooks" + }, + "name": { + "description": "Override the name of the hook.", + "type": ["string", "null"] + }, + "entry": { + "description": "Entry is not allowed for predefined hooks.", + "const": false + }, + "language": { + "anyOf": [ + { + "description": "Language must be `system` for predefined hooks (or omitted).", + "type": "string", + "enum": ["system"] + }, + { + "type": "null" + } + ] + }, + "priority": { + "description": "Priority used by the scheduler to determine ordering and concurrency.\nHooks with the same priority can run in parallel.\n\nThis is only allowed in project config files (e.g. `.pre-commit-config.yaml`).\nIt is not allowed in manifests (e.g. `.pre-commit-hooks.yaml`).", + "type": ["integer", "null"], + "minimum": 0 + }, + "alias": { + "description": "Not documented in the official docs.", + "type": ["string", "null"] + }, + "files": { + "description": "The pattern of files to run on.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "exclude": { + "description": "Exclude files that were matched by `files`.\nDefault is `$^`, which matches nothing.", + "anyOf": [ + { + "$ref": "#/definitions/FilePattern" + }, + { + "type": "null" + } + ] + }, + "types": { + "description": "List of file types to run on (AND).\nDefault is `[file]`, which matches all files.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "types_or": { + "description": "List of file types to run on (OR).\nDefault is `[]`.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "exclude_types": { + "description": "List of file types to exclude.\nDefault is `[]`.", + "type": ["array", "null"], + "items": { + "type": "string" + }, + "default": null + }, + "additional_dependencies": { + "description": "Not documented in the official docs.", + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "args": { + "description": "Additional arguments to pass to the hook.", + "type": ["array", "null"], + "items": { + "type": "string" + } + }, + "env": { + "description": "Environment variables to set for the hook.", + "type": ["object", "null"], + "additionalProperties": { + "type": "string" + } + }, + "always_run": { + "description": "This hook will run even if there are no matching files.\nDefault is false.", + "type": ["boolean", "null"] + }, + "fail_fast": { + "description": "If this hook fails, don't run any more hooks.\nDefault is false.", + "type": ["boolean", "null"] + }, + "pass_filenames": { + "description": "Append filenames that would be checked to the hook entry as arguments.\nDefault is true.", + "type": ["boolean", "null"] + }, + "description": { + "description": "A description of the hook. For metadata only.", + "type": ["string", "null"] + }, + "language_version": { + "description": "Run the hook on a specific version of the language.\nDefault is `default`.\nSee .", + "type": ["string", "null"] + }, + "log_file": { + "description": "Write the output of the hook to a file when the hook fails or verbose is enabled.", + "type": ["string", "null"] + }, + "require_serial": { + "description": "This hook will execute using a single process instead of in parallel.\nDefault is false.", + "type": ["boolean", "null"] + }, + "stages": { + "description": "Select which git hook(s) to run for.\nDefault all stages are selected.\nSee .", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Stage" + } + }, + "verbose": { + "description": "Print the output of the hook even if it passes.\nDefault is false.", + "type": ["boolean", "null"] + }, + "minimum_prek_version": { + "description": "The minimum version of prek required to run this hook.", + "type": ["string", "null"], + "default": null + } + }, + "required": ["id"], + "additionalProperties": true + }, + "BuiltinHooks": { + "type": "string", + "enum": [ + "check-added-large-files", + "check-case-conflict", + "check-executables-have-shebangs", + "check-json", + "check-json5", + "check-merge-conflict", + "check-symlinks", + "check-toml", + "check-xml", + "check-yaml", + "detect-private-key", + "end-of-file-fixer", + "fix-byte-order-marker", + "mixed-line-ending", + "no-commit-to-branch", + "trailing-whitespace" + ] + }, + "HookType": { + "type": "string", + "enum": [ + "commit-msg", + "post-checkout", + "post-commit", + "post-merge", + "post-rewrite", + "pre-commit", + "pre-merge-commit", + "pre-push", + "pre-rebase", + "prepare-commit-msg" + ] + } + } +} diff --git a/src/schemas/json/rumdl.json b/src/schemas/json/rumdl.json index 1c90dc86894..dbb83722a25 100644 --- a/src/schemas/json/rumdl.json +++ b/src/schemas/json/rumdl.json @@ -40,6 +40,21 @@ "$ref": "#/definitions/MarkdownFlavor" }, "default": {} + }, + "code-block-tools": { + "$ref": "#/definitions/CodeBlockToolsConfig", + "description": "Code block tools configuration for per-language linting and formatting\nusing external tools like ruff, prettier, shellcheck, etc.", + "default": { + "enabled": false, + "normalize-language": "linguist", + "on-error": "fail", + "on-missing-language-definition": "ignore", + "on-missing-tool-binary": "ignore", + "timeout": 30000, + "languages": {}, + "language-aliases": {}, + "tools": {} + } } }, "additionalProperties": { @@ -118,7 +133,7 @@ "default": "standard" }, "force-exclude": { - "description": "[DEPRECATED] Whether to enforce exclude patterns for explicitly passed paths.\nThis option is deprecated as of v0.0.156 and has no effect.\nExclude patterns are now always respected, even for explicitly provided files.\nThis prevents duplication between rumdl config and tool configs like pre-commit.", + "description": "\\[DEPRECATED\\] Whether to enforce exclude patterns for explicitly passed paths.\nThis option is deprecated as of v0.0.156 and has no effect.\nExclude patterns are now always respected, even for explicitly provided files.\nThis prevents duplication between rumdl config and tool configs like pre-commit.", "type": "boolean", "deprecated": true, "default": false @@ -156,6 +171,196 @@ "obsidian" ] }, + "CodeBlockToolsConfig": { + "description": "Master configuration for code block tools.\n\nThis is disabled by default for safety - users must explicitly enable it.", + "type": "object", + "properties": { + "enabled": { + "description": "Master switch (default: false)", + "type": "boolean", + "default": false + }, + "normalize-language": { + "$ref": "#/definitions/NormalizeLanguage", + "description": "Language normalization strategy", + "default": "linguist" + }, + "on-error": { + "$ref": "#/definitions/OnError", + "description": "Global error handling strategy", + "default": "fail" + }, + "on-missing-language-definition": { + "$ref": "#/definitions/OnMissing", + "description": "Behavior when a code block language has no tools configured for the current mode\n(e.g., no lint tools for `rumdl check`, no format tools for `rumdl check --fix`)", + "default": "ignore" + }, + "on-missing-tool-binary": { + "$ref": "#/definitions/OnMissing", + "description": "Behavior when a configured tool's binary cannot be found (e.g., not in PATH)", + "default": "ignore" + }, + "timeout": { + "description": "Timeout per tool execution in milliseconds (default: 30000)", + "type": "integer", + "minimum": 0, + "default": 30000 + }, + "languages": { + "description": "Per-language tool configuration", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/LanguageToolConfig" + }, + "default": {} + }, + "language-aliases": { + "description": "User-defined language aliases (override built-in resolution)\nExample: { \"py\": \"python\", \"bash\": \"shell\" }", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "default": {} + }, + "tools": { + "description": "Custom tool definitions (override built-ins)", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ToolDefinition" + }, + "default": {} + } + } + }, + "NormalizeLanguage": { + "description": "Language normalization strategy.", + "oneOf": [ + { + "description": "Resolve language aliases using GitHub Linguist data (e.g., \"py\" -> \"python\")", + "type": "string", + "const": "linguist" + }, + { + "description": "Use the language tag exactly as written in the code block", + "type": "string", + "const": "exact" + } + ] + }, + "OnError": { + "description": "Error handling strategy for tool execution failures.", + "oneOf": [ + { + "description": "Fail the lint/format operation (propagate error)", + "type": "string", + "const": "fail" + }, + { + "description": "Skip the code block and continue processing", + "type": "string", + "const": "skip" + }, + { + "description": "Log a warning but continue processing", + "type": "string", + "const": "warn" + } + ] + }, + "OnMissing": { + "description": "Behavior when a language has no tools configured or a tool binary is missing.", + "oneOf": [ + { + "description": "Silently skip and continue processing (default for backward compatibility)", + "type": "string", + "const": "ignore" + }, + { + "description": "Record an error for that block, continue processing, exit non-zero at the end", + "type": "string", + "const": "fail" + }, + { + "description": "Stop immediately on the first occurrence, exit non-zero", + "type": "string", + "const": "fail-fast" + } + ] + }, + "LanguageToolConfig": { + "description": "Per-language tool configuration.", + "type": "object", + "properties": { + "lint": { + "description": "Tools to run in lint mode (rumdl check)", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "format": { + "description": "Tools to run in format mode (rumdl check --fix / rumdl fmt)", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "on-error": { + "description": "Override global on-error setting for this language", + "anyOf": [ + { + "$ref": "#/definitions/OnError" + }, + { + "type": "null" + } + ], + "default": null + } + } + }, + "ToolDefinition": { + "description": "Definition of an external tool.\n\nThis describes how to invoke a tool and how it communicates.", + "type": "object", + "properties": { + "command": { + "description": "Command to run (first element is the binary, rest are arguments)", + "type": "array", + "items": { + "type": "string" + } + }, + "stdin": { + "description": "Whether the tool reads from stdin (default: true)", + "type": "boolean", + "default": true + }, + "stdout": { + "description": "Whether the tool writes to stdout (default: true)", + "type": "boolean", + "default": true + }, + "lint-args": { + "description": "Additional arguments for lint mode (appended to command)", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "format-args": { + "description": "Additional arguments for format mode (appended to command)", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + }, + "required": ["command"] + }, "RuleConfig": { "description": "Represents a rule-specific configuration", "type": "object", diff --git a/src/schemas/json/snowflake-config.json b/src/schemas/json/snowflake-config.json index fef18c1b6b3..6564724a2fc 100644 --- a/src/schemas/json/snowflake-config.json +++ b/src/schemas/json/snowflake-config.json @@ -132,10 +132,15 @@ "id_token", "no_auth", "oauth", + "oauth_client_credentials", + "oauth_authorization_code", + "okta", "programmatic_access_token", "snowflake_jwt", "snowflake", - "username_password_mfa" + "tokenaccessor", + "username_password_mfa", + "workload_identity" ], "default": "snowflake" }, @@ -163,6 +168,17 @@ "type": "string", "title": "Token File Path for OAuth", "description": "The path to the token file for the Snowflake OAuth Authentication" + }, + "workload_identity_provider": { + "type": "string", + "title": "Workload Identity Provider", + "description": "The workload identity provider to use for WIF authentication", + "enum": ["azure", "aws", "gcp", "oidc"] + }, + "workload_identity_entra_resource": { + "type": "string", + "title": "Workload Identity Entra Resource", + "description": "e resource to use for WIF authentication on Azure environment" } }, "additionalProperties": true, diff --git a/src/schemas/json/snowflake-connections.json b/src/schemas/json/snowflake-connections.json index 5a9efcc1063..94c4085a2ff 100644 --- a/src/schemas/json/snowflake-connections.json +++ b/src/schemas/json/snowflake-connections.json @@ -70,10 +70,15 @@ "id_token", "no_auth", "oauth", + "oauth_client_credentials", + "oauth_authorization_code", + "okta", "programmatic_access_token", "snowflake_jwt", "snowflake", - "username_password_mfa" + "tokenaccessor", + "username_password_mfa", + "workload_identity" ], "default": "snowflake" }, @@ -101,6 +106,17 @@ "type": "string", "title": "Token File Path for OAuth", "description": "The path to the token file for the Snowflake OAuth Authentication" + }, + "workload_identity_provider": { + "type": "string", + "title": "Workload Identity Provider", + "description": "The workload identity provider to use for WIF authentication", + "enum": ["azure", "aws", "gcp", "oidc"] + }, + "workload_identity_entra_resource": { + "type": "string", + "title": "Workload Identity Entra Resource", + "description": "e resource to use for WIF authentication on Azure environment" } }, "additionalProperties": true, diff --git a/src/schemas/json/ty.json b/src/schemas/json/ty.json index f87b0b091e9..679b8a08f4f 100644 --- a/src/schemas/json/ty.json +++ b/src/schemas/json/ty.json @@ -37,7 +37,7 @@ ] }, "rules": { - "description": "Configures the enabled rules and their severity.\n\nSee [the rules documentation](https://ty.dev/rules) for a list of all available rules.\n\nValid severities are:\n\n* `ignore`: Disable the rule.\n* `warn`: Enable the rule and create a warning diagnostic.\n* `error`: Enable the rule and create an error diagnostic.\n ty will exit with a non-zero code if any error diagnostics are emitted.", + "description": "Configures the enabled rules and their severity.\n\nThe keys are either rule names or `all` to set a default severity for all rules.\nSee [the rules documentation](https://ty.dev/rules) for a list of all available rules.\n\nValid severities are:\n\n* `ignore`: Disable the rule.\n* `warn`: Enable the rule and create a warning diagnostic.\n* `error`: Enable the rule and create an error diagnostic.\n ty will exit with a non-zero code if any error diagnostics are emitted.", "anyOf": [ { "$ref": "#/definitions/Rules" @@ -73,6 +73,13 @@ "AnalysisOptions": { "type": "object", "properties": { + "allowed-unresolved-imports": { + "description": "A list of module glob patterns for which `unresolved-import` diagnostics should be suppressed.\n\nDetails on supported glob patterns:\n- `*` matches zero or more characters except `.`. For example, `foo.*` matches `foo.bar` but\n not `foo.bar.baz`; `foo*` matches `foo` and `foobar` but not `foo.bar` or `barfoo`; and `*foo`\n matches `foo` and `barfoo` but not `foo.bar` or `foobar`.\n- `**` matches any number of module components (e.g., `foo.**` matches `foo`, `foo.bar`, etc.)\n- Prefix a pattern with `!` to exclude matching modules\n\nWhen multiple patterns match, later entries take precedence.\n\nGlob patterns can be used in combinations with each other. For example, to suppress errors for\nany module where the first component contains the substring `test`, use `*test*.**`.", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/string" + } + }, "respect-type-ignore-comments": { "description": "Whether ty should respect `type: ignore` comments.\n\nWhen set to `false`, `type: ignore` comments are treated like any other normal\ncomment and can't be used to suppress ty errors (you have to use `ty: ignore` instead).\n\nSetting this option can be useful when using ty alongside other type checkers or when\nyou prefer using `ty: ignore` over `type: ignore`.\n\nDefaults to `true`.", "type": ["boolean", "null"] @@ -332,6 +339,16 @@ "Rules": { "type": "object", "properties": { + "abstract-method-in-final-class": { + "title": "detects `@final` classes with unimplemented abstract methods", + "description": "## What it does\nChecks for `@final` classes that have unimplemented abstract methods.\n\n## Why is this bad?\nA class decorated with `@final` cannot be subclassed. If such a class has abstract\nmethods that are not implemented, the class can never be properly instantiated, as\nthe abstract methods can never be implemented (since subclassing is prohibited).\n\nAt runtime, instantiation of classes with unimplemented abstract methods is only\nprevented for classes that have `ABCMeta` (or a subclass of it) as their metaclass.\nHowever, type checkers also enforce this for classes that do not use `ABCMeta`, since\nthe intent for the class to be abstract is clear from the use of `@abstractmethod`.\n\n## Example\n\n```python\nfrom abc import ABC, abstractmethod\nfrom typing import final\n\nclass Base(ABC):\n @abstractmethod\n def method(self) -> int: ...\n\n@final\nclass Derived(Base): # Error: `Derived` does not implement `method`\n pass\n```", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, "ambiguous-protocol-member": { "title": "detects protocol classes with ambiguous interfaces", "description": "## What it does\nChecks for protocol classes with members that will lead to ambiguous interfaces.\n\n## Why is this bad?\nAssigning to an undeclared variable in a protocol class leads to an ambiguous\ninterface which may lead to the type checker inferring unexpected things. It's\nrecommended to ensure that all members of a protocol class are explicitly declared.\n\n## Examples\n\n```py\nfrom typing import Protocol\n\nclass BaseProto(Protocol):\n a: int # fine (explicitly declared as `int`)\n def method_member(self) -> int: ... # fine: a method definition using `def` is considered a declaration\n c = \"some variable\" # error: no explicit declaration, leading to ambiguity\n b = method_member # error: no explicit declaration, leading to ambiguity\n\n # error: this creates implicit assignments of `d` and `e` in the protocol class body.\n # Were they really meant to be considered protocol members?\n for d, e in enumerate(range(42)):\n pass\n\nclass SubProto(BaseProto, Protocol):\n a = 42 # fine (declared in superclass)\n```", @@ -342,6 +359,16 @@ } ] }, + "assert-type-unspellable-subtype": { + "title": "detects failed type assertions", + "description": "## What it does\nChecks for `assert_type()` calls where the actual type\nis an unspellable subtype of the asserted type.\n\n## Why is this bad?\n`assert_type()` is intended to ensure that the inferred type of a value\nis exactly the same as the asserted type. But in some situations, ty\nhas nonstandard extensions to the type system that allow it to infer\nmore precise types than can be expressed in user annotations. ty emits a\ndifferent error code to `type-assertion-failure` in these situations so\nthat users can easily differentiate between the two cases.\n\n## Example\n\n```python\ndef _(x: int):\n assert_type(x, int) # fine\n if x:\n assert_type(x, int) # error: [assert-type-unspellable-subtype]\n # the actual type is `int & ~AlwaysFalsy`,\n # which excludes types like `Literal[0]`\n```", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, "byte-string-type-annotation": { "title": "detects byte strings in type annotation positions", "description": "## What it does\nChecks for byte-strings in type annotation positions.\n\n## Why is this bad?\nStatic analysis tools like ty can't analyze type annotations that use byte-string notation.\n\n## Examples\n```python\ndef test(): -> b\"int\":\n ...\n```\n\nUse instead:\n```python\ndef test(): -> \"int\":\n ...\n```", @@ -422,6 +449,16 @@ } ] }, + "dataclass-field-order": { + "title": "detects dataclass definitions with required fields after fields with default values", + "description": "## What it does\nChecks for dataclass definitions where required fields are defined after\nfields with default values.\n\n## Why is this bad?\nIn dataclasses, all required fields (fields without default values) must be\ndefined before fields with default values. This is a Python requirement that\nwill raise a `TypeError` at runtime if violated.\n\n## Example\n```python\nfrom dataclasses import dataclass\n\n@dataclass\nclass Example:\n x: int = 1 # Field with default value\n y: str # Error: Required field after field with default\n```", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, "deprecated": { "title": "detects uses of deprecated items", "description": "## What it does\nChecks for uses of deprecated items\n\n## Why is this bad?\nDeprecated items should no longer be used.\n\n## Examples\n```python\n@warnings.deprecated(\"use new_func instead\")\ndef old_func(): ...\n\nold_func() # emits [deprecated] diagnostic\n```", @@ -462,6 +499,16 @@ } ] }, + "empty-body": { + "title": "detects functions with empty bodies that have a non-`None` return type annotation", + "description": "## What it does\nDetects functions with empty bodies that have a non-`None` return type annotation.\n\nThe errors reported by this rule have the same motivation as the `invalid-return-type`\nrule. The diagnostic exists as a separate error code to allow users to disable this\nrule while prototyping code. While we strongly recommend enabling this rule if\npossible, users migrating from other type checkers may also find it useful to\ntemporarily disable this rule on some or all of their codebase if they find it\nresults in a large number of diagnostics.\n\n## Why is this bad?\nA function with an empty body (containing only `...`, `pass`, or a docstring) will\nimplicitly return `None` at runtime. Returning `None` when the return type is non-`None`\nis unsound, and will lead to ty inferring incorrect types elsewhere.\n\nFunctions with empty bodies are permitted in certain contexts where they serve as\ndeclarations rather than implementations:\n\n- Functions in stub files (`.pyi`)\n- Methods in Protocol classes\n- Abstract methods decorated with `@abstractmethod`\n- Overload declarations decorated with `@overload`\n- Functions in `if TYPE_CHECKING` blocks\n\n## Examples\n```python\ndef foo() -> int: ... # error: [empty-body]\n\ndef bar() -> str:\n \"\"\"A function that does nothing.\"\"\"\n pass # error: [empty-body]\n```", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, "escape-character-in-forward-annotation": { "title": "detects forward type annotations with escape characters", "description": "## What it does\nChecks for forward annotations that contain escape characters.\n\n## Why is this bad?\nStatic analysis tools like ty can't analyze type annotations that contain escape characters.\n\n## Example\n\n```python\ndef foo() -> \"intt\\b\": ...\n```", @@ -472,6 +519,16 @@ } ] }, + "final-without-value": { + "title": "detects `Final` declarations without a value", + "description": "## What it does\nChecks for `Final` symbols that are declared without a value and are never\nassigned a value in their scope.\n\n## Why is this bad?\nA `Final` symbol must be initialized with a value at the time of declaration\nor in a subsequent assignment. At module or function scope, the assignment must\noccur in the same scope. In a class body, the assignment may occur in `__init__`.\n\n## Examples\n```python\nfrom typing import Final\n\n# Error: `Final` symbol without a value\nMY_CONSTANT: Final[int]\n\n# OK: `Final` symbol with a value\nMY_CONSTANT: Final[int] = 1\n```", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, "fstring-type-annotation": { "title": "detects F-strings in type annotation positions", "description": "## What it does\nChecks for f-strings in type annotation positions.\n\n## Why is this bad?\nStatic analysis tools like ty can't analyze type annotations that use f-string notation.\n\n## Examples\n```python\ndef test(): -> f\"int\":\n ...\n```\n\nUse instead:\n```python\ndef test(): -> \"int\":\n ...\n```", @@ -702,6 +759,16 @@ } ] }, + "invalid-legacy-positional-parameter": { + "title": "detects incorrect usage of the legacy convention for specifying positional-only parameters", + "description": "## What it does\n\nChecks for parameters that appear to be attempting to use the legacy convention\nto specify that a parameter is positional-only, but do so incorrectly.\n\nThe \"legacy convention\" for specifying positional-only parameters was\nspecified in [PEP 484]. It states that parameters with names starting with\n`__` should be considered positional-only by type checkers. [PEP 570], introduced\nin Python 3.8, added dedicated syntax for specifying positional-only parameters,\nrendering the legacy convention obsolete. However, some codebases may still\nuse the legacy convention for compatibility with older Python versions.\n\n## Why is this bad?\n\nIn most cases, a type checker will not consider a parameter to be positional-only\nif it comes after a positional-or-keyword parameter, even if its name starts with\n`__`. This may be unexpected to the author of the code.\n\n## Example\n\n```python\ndef f(x, __y): # Error: `__y` is not considered positional-only\n pass\n```\n\nUse instead:\n\n```python\ndef f(__x, __y): # If you need compatibility with Python <=3.7\n pass\n```\n\nor:\n\n```python\ndef f(x, y, /): # Python 3.8+ syntax\n pass\n```\n\n## References\n\n- [Typing spec: positional-only parameters (legacy syntax)](https://typing.python.org/en/latest/spec/historical.html#pos-only-double-underscore)\n- [Python glossary: parameters](https://docs.python.org/3/glossary.html#term-parameter)\n\n[PEP 484]: https://peps.python.org/pep-0484/#positional-only-arguments\n[PEP 570]: https://peps.python.org/pep-0570/", + "default": "warn", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, "invalid-legacy-type-variable": { "title": "detects invalid legacy type variables", "description": "## What it does\nChecks for the creation of invalid legacy `TypeVar`s\n\n## Why is this bad?\nThere are several requirements that you must follow when creating a legacy `TypeVar`.\n\n## Examples\n```python\nfrom typing import TypeVar\n\nT = TypeVar(\"T\") # okay\nQ = TypeVar(\"S\") # error: TypeVar name must match the variable it's assigned to\nT = TypeVar(\"T\") # error: TypeVars should not be redefined\n\n# error: TypeVar must be immediately assigned to a variable\ndef f(t: TypeVar(\"U\")): ...\n```\n\n## References\n- [Typing spec: Generics](https://typing.python.org/en/latest/spec/generics.html#introduction)", @@ -804,7 +871,7 @@ }, "invalid-return-type": { "title": "detects returned values that can't be assigned to the function's annotated return type", - "description": "## What it does\nDetects returned values that can't be assigned to the function's annotated return type.\n\n## Why is this bad?\nReturning an object of a type incompatible with the annotated return type may cause confusion to the user calling the function.\n\n## Examples\n```python\ndef func() -> int:\n return \"a\" # error: [invalid-return-type]\n```", + "description": "## What it does\nDetects returned values that can't be assigned to the function's annotated return type.\n\nNote that the special case of a function with a non-`None` return type and an empty body\nis handled by the separate `empty-body` error code.\n\n## Why is this bad?\nReturning an object of a type incompatible with the annotated return type\nis unsound, and will lead to ty inferring incorrect types elsewhere.\n\n## Examples\n```python\ndef func() -> int:\n return \"a\" # error: [invalid-return-type]\n```", "default": "error", "oneOf": [ { @@ -902,9 +969,29 @@ } ] }, + "invalid-type-variable-bound": { + "title": "detects invalid type variable bounds", + "description": "## What it does\nChecks for [type variables] whose bounds reference type variables.\n\n## Why is this bad?\nThe bound of a type variable must be a concrete type.\n\n## Examples\n```python\nT = TypeVar('T', bound=list['T']) # error: [invalid-type-variable-bound]\nU = TypeVar('U')\nT = TypeVar('T', bound=U) # error: [invalid-type-variable-bound]\n\ndef f[T: list[T]](): ... # error: [invalid-type-variable-bound]\ndef g[U, T: U](): ... # error: [invalid-type-variable-bound]\n```\n\n[type variable]: https://docs.python.org/3/library/typing.html#typing.TypeVar", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, "invalid-type-variable-constraints": { "title": "detects invalid type variable constraints", - "description": "## What it does\nChecks for constrained [type variables] with only one constraint.\n\n## Why is this bad?\nA constrained type variable must have at least two constraints.\n\n## Examples\n```python\nfrom typing import TypeVar\n\nT = TypeVar('T', str) # invalid constrained TypeVar\n```\n\nUse instead:\n```python\nT = TypeVar('T', str, int) # valid constrained TypeVar\n# or\nT = TypeVar('T', bound=str) # valid bound TypeVar\n```\n\n[type variables]: https://docs.python.org/3/library/typing.html#typing.TypeVar", + "description": "## What it does\n\nChecks for constrained [type variables] with only one constraint,\nor that those constraints reference type variables.\n\n## Why is this bad?\n\nA constrained type variable must have at least two constraints.\n\n## Examples\n\n```python\nfrom typing import TypeVar\n\nT = TypeVar('T', str) # invalid constrained TypeVar\n\nI = TypeVar('I', bound=int)\nU = TypeVar('U', list[I], int) # invalid constrained TypeVar\n```\n\nUse instead:\n\n```python\nT = TypeVar('T', str, int) # valid constrained TypeVar\n\n# or\n\nT = TypeVar('T', bound=str) # valid bound TypeVar\n\nU = TypeVar('U', list[int], int) # valid constrained Type\n```\n\n[type variables]: https://docs.python.org/3/library/typing.html#typing.TypeVar", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, + "invalid-typed-dict-header": { + "title": "detects invalid statements in `TypedDict` class headers", + "description": "## What it does\nDetects errors in `TypedDict` class headers, such as unexpected arguments\nor invalid base classes.\n\n## Why is this bad?\nThe typing spec states that `TypedDict`s are not permitted to have\ncustom metaclasses. Using `**` unpacking in a `TypedDict` header\nis also prohibited by ty, as it means that ty cannot statically determine\nwhether keys in the `TypedDict` are intended to be required or optional.\n\n## Example\n```python\nfrom typing import TypedDict\n\nclass Foo(TypedDict, metaclass=whatever): # error: [invalid-typed-dict-header]\n ...\n\ndef f(x: dict):\n class Bar(TypedDict, **x): # error: [invalid-typed-dict-header]\n ...\n```", "default": "error", "oneOf": [ { @@ -922,6 +1009,26 @@ } ] }, + "isinstance-against-protocol": { + "title": "reports invalid runtime checks against protocol classes", + "description": "## What it does\nReports invalid runtime checks against `Protocol` classes.\nThis includes explicit calls `isinstance()`/`issubclass()` against\nnon-runtime-checkable protocols, `issubclass()` calls against protocols\nthat have non-method members, and implicit `isinstance()` checks against\nnon-runtime-checkable protocols via pattern matching.\n\n## Why is this bad?\nThese calls (implicit or explicit) raise `TypeError` at runtime.\n\n## Examples\n```python\nfrom typing_extensions import Protocol, runtime_checkable\n\nclass HasX(Protocol):\n x: int\n\n@runtime_checkable\nclass HasY(Protocol):\n y: int\n\ndef f(arg: object, arg2: type):\n isinstance(arg, HasX) # error: [isinstance-against-protocol] (not runtime-checkable)\n issubclass(arg2, HasX) # error: [isinstance-against-protocol] (not runtime-checkable)\n\ndef g(arg: object):\n match arg:\n case HasX(): # error: [isinstance-against-protocol] (not runtime-checkable)\n pass\n\ndef h(arg2: type):\n isinstance(arg2, HasY) # fine (runtime-checkable)\n\n # `HasY` is runtime-checkable, but has non-method members,\n # so it still can't be used in `issubclass` checks)\n issubclass(arg2, HasY) # error: [isinstance-against-protocol]\n```\n\n## References\n- [Typing documentation: `@runtime_checkable`](https://docs.python.org/3/library/typing.html#typing.runtime_checkable)", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, + "isinstance-against-typed-dict": { + "title": "reports runtime checks against `TypedDict` classes", + "description": "## What it does\nReports runtime checks against `TypedDict` classes.\nThis includes explicit calls to `isinstance()`/`issubclass()` and implicit\nchecks performed by `match` class patterns.\n\n## Why is this bad?\nUsing a `TypedDict` class in these contexts raises `TypeError` at runtime.\n\n## Examples\n```python\nfrom typing_extensions import TypedDict\n\nclass Movie(TypedDict):\n name: str\n director: str\n\ndef f(arg: object, arg2: type):\n isinstance(arg, Movie) # error: [isinstance-against-typed-dict]\n issubclass(arg2, Movie) # error: [isinstance-against-typed-dict]\n\ndef g(arg: object):\n match arg:\n case Movie(): # error: [isinstance-against-typed-dict]\n pass\n```\n\n## References\n- [Typing specification: `TypedDict`](https://typing.python.org/en/latest/spec/typeddict.html)", + "default": "error", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, "missing-argument": { "title": "detects missing required arguments in a call", "description": "## What it does\nChecks for missing required arguments in a call.\n\n## Why is this bad?\nFailing to provide a required argument will raise a `TypeError` at runtime.\n\n## Examples\n```python\ndef func(x: int): ...\nfunc() # TypeError: func() missing 1 required positional argument: 'x'\n```", @@ -1223,8 +1330,18 @@ ] }, "unused-ignore-comment": { - "title": "detects unused `ty: ignore` and `type: ignore` comments", - "description": "## What it does\nChecks for `ty: ignore` or `type: ignore` directives that are no longer applicable.\n\n## Why is this bad?\nA `ty: ignore` directive that no longer matches any diagnostic violations is likely\nincluded by mistake, and should be removed to avoid confusion.\n\n## Examples\n```py\na = 20 / 2 # ty: ignore[division-by-zero]\n```\n\nUse instead:\n\n```py\na = 20 / 2\n```\n\n## Options\nSet [`analysis.respect-type-ignore-comments`](https://docs.astral.sh/ty/reference/configuration/#respect-type-ignore-comments)\nto `false` to prevent this rule from reporting unused `type: ignore` comments.", + "title": "detects unused `ty: ignore` comments", + "description": "## What it does\nChecks for `ty: ignore` directives that are no longer applicable.\n\n## Why is this bad?\nA `ty: ignore` directive that no longer matches any diagnostic violations is likely\nincluded by mistake, and should be removed to avoid confusion.\n\n## Examples\n```py\na = 20 / 2 # ty: ignore[division-by-zero]\n```\n\nUse instead:\n\n```py\na = 20 / 2\n```\n\n## Options\nSet [`analysis.respect-type-ignore-comments`](https://docs.astral.sh/ty/reference/configuration/#respect-type-ignore-comments)\nto `false` to prevent this rule from reporting unused `type: ignore` comments.", + "default": "warn", + "oneOf": [ + { + "$ref": "#/definitions/Level" + } + ] + }, + "unused-type-ignore-comment": { + "title": "detects unused `type: ignore` comments", + "description": "## What it does\nChecks for `type: ignore` directives that are no longer applicable.\n\n## Why is this bad?\nA `type: ignore` directive that no longer matches any diagnostic violations is likely\nincluded by mistake, and should be removed to avoid confusion.\n\n## Examples\n```py\na = 20 / 2 # type: ignore\n```\n\nUse instead:\n\n```py\na = 20 / 2\n```\n\n## Options\n\nThis rule is skipped if [`analysis.respect-type-ignore-comments`](https://docs.astral.sh/ty/reference/configuration/#respect-type-ignore-comments)\nto `false`.", "default": "warn", "oneOf": [ { diff --git a/src/test/claude-code-settings/hooks-complete.json b/src/test/claude-code-settings/hooks-complete.json index 922b8a4fba7..b1ea64991d9 100644 --- a/src/test/claude-code-settings/hooks-complete.json +++ b/src/test/claude-code-settings/hooks-complete.json @@ -44,6 +44,7 @@ { "hooks": [ { + "async": true, "command": "echo 'Running bash command' >> /tmp/claude-log.txt", "timeout": 5, "type": "command" diff --git a/src/test/claude-code-settings/marketplace-host-pattern.json b/src/test/claude-code-settings/marketplace-host-pattern.json new file mode 100644 index 00000000000..2ceda674c17 --- /dev/null +++ b/src/test/claude-code-settings/marketplace-host-pattern.json @@ -0,0 +1,16 @@ +{ + "extraKnownMarketplaces": { + "internal-git": { + "source": { + "hostPattern": "git.internal.example.com", + "source": "hostPattern" + } + } + }, + "strictKnownMarketplaces": [ + { + "hostPattern": "*.corp.example", + "source": "hostPattern" + } + ] +} diff --git a/src/test/claude-code-settings/modern-complete-config.json b/src/test/claude-code-settings/modern-complete-config.json index 4caee0a228e..da57e3e4044 100644 --- a/src/test/claude-code-settings/modern-complete-config.json +++ b/src/test/claude-code-settings/modern-complete-config.json @@ -15,6 +15,14 @@ "CLAUDE_LOG_LEVEL": "debug", "PROJECT_ROOT": "/home/user/projects" }, + "extraKnownMarketplaces": { + "corp-git-host": { + "source": { + "hostPattern": "git.corp.example", + "source": "hostPattern" + } + } + }, "fileSuggestion": { "command": "~/.claude/file-suggestion.sh", "type": "command" @@ -74,6 +82,19 @@ }, "plansDirectory": "./plans", "respectGitignore": true, + "sandbox": { + "network": { + "allowAllUnixSockets": false, + "allowLocalBinding": true, + "allowedDomains": ["api.anthropic.com", "*.example.com"], + "deniedDomains": ["malware.example"], + "socksProxyPort": 11080 + } + }, "showTurnDuration": true, + "spinnerVerbs": { + "mode": "append", + "verbs": ["Analyzing", "Building"] + }, "terminalProgressBarEnabled": true } diff --git a/src/test/prek/prek.toml b/src/test/prek/prek.toml new file mode 100644 index 00000000000..c0f88544428 --- /dev/null +++ b/src/test/prek/prek.toml @@ -0,0 +1,7 @@ +#:schema ../../schemas/json/prek.json +[[repos]] +repo = "https://github.com/pre-commit/pre-commit-hooks" +rev = "v6.0.0" +hooks = [ + { id = "end-of-file-fixer", args = ["--fix"] }, +]