{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Config",
  "description": "rumdl configuration for linting Markdown files. Rules can be configured individually using [MD###] sections with rule-specific options.",
  "type": "object",
  "properties": {
    "global": {
      "description": "Global configuration options",
      "$ref": "#/$defs/GlobalConfig",
      "default": {
        "enable": [],
        "disable": [],
        "extend-enable": [],
        "extend-disable": [],
        "exclude": [],
        "include": [],
        "respect-gitignore": true,
        "line-length": 80,
        "fixable": [],
        "unfixable": [],
        "flavor": "standard",
        "force-exclude": false,
        "cache": true
      }
    },
    "per-file-ignores": {
      "description": "Per-file rule ignores: maps file patterns to lists of rules to ignore\nExample: { \"README.md\": [\"MD033\"], \"docs/**/*.md\": [\"MD013\"] }",
      "type": "object",
      "additionalProperties": {
        "type": "array",
        "items": {
          "type": "string"
        }
      },
      "default": {}
    },
    "per-file-flavor": {
      "description": "Per-file flavor overrides: maps file patterns to Markdown flavors\nExample: { \"docs/**/*.md\": MkDocs, \"**/*.mdx\": MDX }\nUses IndexMap to preserve config file order for \"first match wins\" semantics",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/MarkdownFlavor"
      },
      "default": {}
    },
    "code-block-tools": {
      "description": "Code block tools configuration for per-language linting and formatting\nusing external tools like ruff, prettier, shellcheck, etc.",
      "$ref": "#/$defs/CodeBlockToolsConfig",
      "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": {
    "$ref": "#/$defs/RuleConfig"
  },
  "$defs": {
    "GlobalConfig": {
      "description": "Global configuration options",
      "type": "object",
      "properties": {
        "enable": {
          "description": "Enabled rules",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "disable": {
          "description": "Disabled rules",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "extend-enable": {
          "description": "Additional rules to enable on top of the base set (additive across config levels)",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "extend-disable": {
          "description": "Additional rules to disable on top of the base set (additive across config levels)",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "exclude": {
          "description": "Files to exclude",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "include": {
          "description": "Files to include",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "respect-gitignore": {
          "description": "Respect .gitignore files when scanning directories",
          "type": "boolean",
          "default": true
        },
        "line-length": {
          "description": "Global line length setting (used by MD013 and other rules if not overridden)",
          "$ref": "#/$defs/LineLength",
          "default": 80
        },
        "output-format": {
          "description": "Output format for linting results (e.g., \"text\", \"json\", \"pylint\", etc.)",
          "type": [
            "string",
            "null"
          ]
        },
        "fixable": {
          "description": "Rules that are allowed to be fixed when --fix is used\nIf specified, only these rules will be fixed",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "unfixable": {
          "description": "Rules that should never be fixed, even when --fix is used\nTakes precedence over fixable",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "flavor": {
          "description": "Markdown flavor/dialect to use (mkdocs, gfm, commonmark, etc.)\nWhen set, adjusts parsing and validation rules for that specific Markdown variant",
          "$ref": "#/$defs/MarkdownFlavor",
          "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.",
          "type": "boolean",
          "deprecated": true,
          "default": false
        },
        "cache-dir": {
          "description": "Directory to store cache files (default: .rumdl_cache)\nCan also be set via --cache-dir CLI flag or RUMDL_CACHE_DIR environment variable",
          "type": [
            "string",
            "null"
          ]
        },
        "cache": {
          "description": "Whether caching is enabled (default: true)\nCan also be disabled via --no-cache CLI flag",
          "type": "boolean",
          "default": true
        }
      }
    },
    "LineLength": {
      "description": "A line length value that can be 0 (meaning no limit) or a positive value (≥1)\n\nMany configuration values for line length need to support both:\n- 0: Special value meaning \"no line length limit\"\n- ≥1: Actual line length limit\n\nThis type enforces those constraints at deserialization time.",
      "type": [
        "integer",
        "null"
      ],
      "format": "uint",
      "minimum": 0
    },
    "MarkdownFlavor": {
      "description": "Markdown flavor/dialect. Accepts: standard, gfm, mkdocs, mdx, quarto, obsidian, kramdown. Aliases: commonmark/github map to standard, qmd/rmd/rmarkdown map to quarto, jekyll maps to kramdown.",
      "type": "string",
      "enum": [
        "standard",
        "gfm",
        "github",
        "commonmark",
        "mkdocs",
        "mdx",
        "quarto",
        "qmd",
        "rmd",
        "rmarkdown",
        "obsidian",
        "kramdown",
        "jekyll"
      ]
    },
    "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": {
          "description": "Language normalization strategy",
          "$ref": "#/$defs/NormalizeLanguage",
          "default": "linguist"
        },
        "on-error": {
          "description": "Global error handling strategy",
          "$ref": "#/$defs/OnError",
          "default": "fail"
        },
        "on-missing-language-definition": {
          "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`)",
          "$ref": "#/$defs/OnMissing",
          "default": "ignore"
        },
        "on-missing-tool-binary": {
          "description": "Behavior when a configured tool's binary cannot be found (e.g., not in PATH)",
          "$ref": "#/$defs/OnMissing",
          "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": "#/$defs/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": "#/$defs/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": "#/$defs/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",
      "properties": {
        "severity": {
          "description": "Severity override for this rule (Error, Warning, or Info)",
          "anyOf": [
            {
              "$ref": "#/$defs/Severity"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "additionalProperties": true
    },
    "Severity": {
      "type": "string",
      "enum": [
        "error",
        "warning",
        "info"
      ]
    }
  }
}