{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "ast-grep rule", "description": "Used for global rules, rewriters, and pyo3/napi", "type": "object", "required": [ "id", "language", "rule" ], "properties": { "constraints": { "description": "Additional meta variables pattern to filter matching", "type": [ "object", "null" ], "additionalProperties": { "$ref": "#/definitions/SerializableRule" } }, "files": { "description": "Glob patterns to specify that the rule only applies to matching files", "type": [ "array", "null" ], "items": { "type": "string" } }, "fix": { "description": "A pattern string or a FixConfig object to auto fix the issue. It can reference metavariables appeared in rule. See details in fix [object reference](https://ast-grep.github.io/reference/yaml/fix.html#fixconfig).", "anyOf": [ { "$ref": "#/definitions/SerializableFixer" }, { "type": "null" } ] }, "id": { "description": "Unique, descriptive identifier, e.g., no-unused-variable", "type": "string" }, "ignores": { "description": "Glob patterns that exclude rules from applying to files", "type": [ "array", "null" ], "items": { "type": "string" } }, "language": { "description": "Specify the language to parse and the file extension to include in matching.", "allOf": [ { "$ref": "#/definitions/Language" } ] }, "message": { "description": "Main message highlighting why this rule fired. It should be single line and concise, but specific enough to be understood without additional context.", "default": "", "type": "string" }, "metadata": { "description": "Extra information for the rule", "type": [ "object", "null" ], "additionalProperties": { "type": "string" } }, "note": { "description": "Additional notes to elaborate the message and provide potential fix to the issue.", "type": [ "string", "null" ] }, "rewriters": { "description": "Rewrite rules for `rewrite` transformation", "type": [ "array", "null" ], "items": { "$ref": "#/definitions/SerializableRewriter" } }, "rule": { "description": "A rule object to find matching AST nodes. We have three categories of rules in ast-grep.\n\n* Atomic: the most basic rule to match AST. We have two variants: Pattern and Kind.\n\n* Relational: filter matched target according to their position relative to other nodes.\n\n* Composite: use logic operation all/any/not to compose the above rules to larger rules.\n\nEvery rule has it's unique name so we can combine several rules in one object.", "allOf": [ { "$ref": "#/definitions/SerializableRule" } ] }, "severity": { "description": "One of: hint, info, warning, or error", "default": "hint", "allOf": [ { "$ref": "#/definitions/Severity" } ] }, "transform": { "description": "A dictionary for metavariable manipulation. Dict key is the new variable name. Dict value is a [transformation] that specifies how meta var is processed. See [transformation doc](https://ast-grep.github.io/reference/yaml/transformation.html).", "type": [ "object", "null" ], "additionalProperties": { "$ref": "#/definitions/Transformation_for_String" } }, "url": { "description": "Documentation link to this rule", "type": [ "string", "null" ] }, "utils": { "description": "Utility rules that can be used in `matches`", "type": [ "object", "null" ], "additionalProperties": { "$ref": "#/definitions/SerializableRule" } } }, "definitions": { "Convert_for_String": { "description": "Converts the source meta variable's text content to a specified case format.", "type": "object", "required": [ "source", "toCase" ], "properties": { "separatedBy": { "description": "optional separators to specify how to separate word", "type": [ "array", "null" ], "items": { "$ref": "#/definitions/Separator" } }, "source": { "description": "source meta variable to be transformed", "type": "string" }, "toCase": { "description": "the target case format to convert the text content to", "allOf": [ { "$ref": "#/definitions/StringCase" } ] } } }, "Language": { "type": "string" }, "Maybe_Array_of_SerializableRule": { "type": "array", "items": { "$ref": "#/definitions/SerializableRule" } }, "Maybe_PatternStyle": { "$ref": "#/definitions/PatternStyle" }, "Maybe_Relation": { "$ref": "#/definitions/Relation" }, "Maybe_SerializableNthChild": { "$ref": "#/definitions/SerializableNthChild" }, "Maybe_SerializableRange": { "$ref": "#/definitions/SerializableRange" }, "Maybe_SerializableRule": { "$ref": "#/definitions/SerializableRule" }, "Maybe_String": { "type": "string" }, "NthChildSimple": { "description": "A string or number describing the indices of matching nodes in a list of siblings.", "anyOf": [ { "description": "A number indicating the precise element index", "type": "integer", "format": "uint", "minimum": 0.0 }, { "description": "Functional notation like CSS's An + B", "type": "string" } ] }, "PatternStyle": { "description": "A String pattern will match one single AST node according to pattern syntax. Or an object with field `context`, `selector` and optionally `strictness`.", "anyOf": [ { "type": "string" }, { "type": "object", "required": [ "context" ], "properties": { "context": { "description": "The surrounding code that helps to resolve any ambiguity in the syntax.", "type": "string" }, "selector": { "description": "The sub-syntax node kind that is the actual matcher of the pattern.", "type": [ "string", "null" ] }, "strictness": { "description": "Strictness of the pattern. More strict pattern matches fewer nodes.", "anyOf": [ { "$ref": "#/definitions/Strictness" }, { "type": "null" } ] } } } ] }, "Relation": { "type": "object", "properties": { "all": { "description": "A list of sub rules and matches a node if all of sub rules match. The meta variables of the matched node contain all variables from the sub-rules.", "allOf": [ { "$ref": "#/definitions/Maybe_Array_of_SerializableRule" } ] }, "any": { "description": "A list of sub rules and matches a node if any of sub rules match. The meta variables of the matched node only contain those of the matched sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Array_of_SerializableRule" } ] }, "field": { "type": [ "string", "null" ] }, "follows": { "description": "`follows` accepts a relational rule object. the target node must appear after another node matching the `follows` sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Relation" } ] }, "has": { "description": "`has` accepts a relational rule object. the target node must has a descendant node matching the `has` sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Relation" } ] }, "inside": { "description": "`inside` accepts a relational rule object. the target node must appear inside of another node matching the `inside` sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Relation" } ] }, "kind": { "description": "The kind name of the node to match. You can look up code's kind names in playground.", "allOf": [ { "$ref": "#/definitions/Maybe_String" } ] }, "matches": { "description": "A utility rule id and matches a node if the utility rule matches.", "allOf": [ { "$ref": "#/definitions/Maybe_String" } ] }, "not": { "description": "A single sub-rule and matches a node if the sub rule does not match.", "allOf": [ { "$ref": "#/definitions/Maybe_SerializableRule" } ] }, "nthChild": { "description": "`nth_child` accepts number, string or object. It specifies the position in nodes' sibling list.", "allOf": [ { "$ref": "#/definitions/Maybe_SerializableNthChild" } ] }, "pattern": { "description": "A pattern string or a pattern object.", "allOf": [ { "$ref": "#/definitions/Maybe_PatternStyle" } ] }, "precedes": { "description": "`precedes` accepts a relational rule object. the target node must appear before another node matching the `precedes` sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Relation" } ] }, "range": { "description": "`range` accepts a range object. the target node must exactly appear in the range.", "allOf": [ { "$ref": "#/definitions/Maybe_SerializableRange" } ] }, "regex": { "description": "A Rust regular expression to match the node's text. https://docs.rs/regex/latest/regex/#syntax", "allOf": [ { "$ref": "#/definitions/Maybe_String" } ] }, "stopBy": { "default": "neighbor", "allOf": [ { "$ref": "#/definitions/SerializableStopBy" } ] } } }, "Replace_for_String": { "description": "Replaces a substring in the meta variable's text content with another string.", "type": "object", "required": [ "by", "replace", "source" ], "properties": { "by": { "description": "the replacement string", "type": "string" }, "replace": { "description": "a regex to find substring to be replaced", "type": "string" }, "source": { "description": "source meta variable to be transformed", "type": "string" } } }, "Rewrite_for_String": { "type": "object", "required": [ "rewriters", "source" ], "properties": { "joinBy": { "type": [ "string", "null" ] }, "rewriters": { "type": "array", "items": { "type": "string" } }, "source": { "type": "string" } } }, "Separator": { "description": "Separator to split string. e.g. `user_accountName` -> `user`, `accountName` It will be rejoin according to `StringCase`.", "type": "string", "enum": [ "caseChange", "dash", "dot", "slash", "space", "underscore" ] }, "SerializableFixConfig": { "type": "object", "required": [ "template" ], "properties": { "expandEnd": { "$ref": "#/definitions/Maybe_Relation" }, "expandStart": { "$ref": "#/definitions/Maybe_Relation" }, "template": { "type": "string" } } }, "SerializableFixer": { "description": "A pattern string or fix object to auto fix the issue. It can reference metavariables appeared in rule.", "anyOf": [ { "type": "string" }, { "$ref": "#/definitions/SerializableFixConfig" } ] }, "SerializableNthChild": { "description": "`nthChild` accepts either a number, a string or an object.", "anyOf": [ { "description": "Simple syntax", "allOf": [ { "$ref": "#/definitions/NthChildSimple" } ] }, { "description": "Object style syntax", "type": "object", "required": [ "position" ], "properties": { "ofRule": { "description": "select the nth node that matches the rule, like CSS's of syntax", "anyOf": [ { "$ref": "#/definitions/SerializableRule" }, { "type": "null" } ] }, "position": { "description": "nth-child syntax", "allOf": [ { "$ref": "#/definitions/NthChildSimple" } ] }, "reverse": { "description": "matches from the end instead like CSS's nth-last-child", "default": false, "type": "boolean" } } } ] }, "SerializablePosition": { "description": "Represents a zero-based character-wise position in a document", "type": "object", "required": [ "column", "line" ], "properties": { "column": { "description": "0-based column number in the source code", "type": "integer", "format": "uint", "minimum": 0.0 }, "line": { "description": "0-based line number in the source code", "type": "integer", "format": "uint", "minimum": 0.0 } } }, "SerializableRange": { "description": "Represents a position in source code using 0-based line and column numbers", "type": "object", "required": [ "end", "start" ], "properties": { "end": { "description": "end position in the source code", "allOf": [ { "$ref": "#/definitions/SerializablePosition" } ] }, "start": { "description": "start position in the source code", "allOf": [ { "$ref": "#/definitions/SerializablePosition" } ] } } }, "SerializableRewriter": { "description": "Used for global rules, rewriters, and pyo3/napi", "type": "object", "required": [ "id", "rule" ], "properties": { "constraints": { "description": "Additional meta variables pattern to filter matching", "type": [ "object", "null" ], "additionalProperties": { "$ref": "#/definitions/SerializableRule" } }, "fix": { "description": "A pattern string or a FixConfig object to auto fix the issue. It can reference metavariables appeared in rule. See details in fix [object reference](https://ast-grep.github.io/reference/yaml/fix.html#fixconfig).", "anyOf": [ { "$ref": "#/definitions/SerializableFixer" }, { "type": "null" } ] }, "id": { "description": "Unique, descriptive identifier, e.g., no-unused-variable", "type": "string" }, "rule": { "description": "A rule object to find matching AST nodes", "allOf": [ { "$ref": "#/definitions/SerializableRule" } ] }, "transform": { "description": "A dictionary for metavariable manipulation. Dict key is the new variable name. Dict value is a [transformation] that specifies how meta var is processed. See [transformation doc](https://ast-grep.github.io/reference/yaml/transformation.html).", "type": [ "object", "null" ], "additionalProperties": { "$ref": "#/definitions/Transformation_for_String" } }, "utils": { "description": "Utility rules that can be used in `matches`", "type": [ "object", "null" ], "additionalProperties": { "$ref": "#/definitions/SerializableRule" } } } }, "SerializableRule": { "type": "object", "properties": { "all": { "description": "A list of sub rules and matches a node if all of sub rules match. The meta variables of the matched node contain all variables from the sub-rules.", "allOf": [ { "$ref": "#/definitions/Maybe_Array_of_SerializableRule" } ] }, "any": { "description": "A list of sub rules and matches a node if any of sub rules match. The meta variables of the matched node only contain those of the matched sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Array_of_SerializableRule" } ] }, "follows": { "description": "`follows` accepts a relational rule object. the target node must appear after another node matching the `follows` sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Relation" } ] }, "has": { "description": "`has` accepts a relational rule object. the target node must has a descendant node matching the `has` sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Relation" } ] }, "inside": { "description": "`inside` accepts a relational rule object. the target node must appear inside of another node matching the `inside` sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Relation" } ] }, "kind": { "description": "The kind name of the node to match. You can look up code's kind names in playground.", "allOf": [ { "$ref": "#/definitions/Maybe_String" } ] }, "matches": { "description": "A utility rule id and matches a node if the utility rule matches.", "allOf": [ { "$ref": "#/definitions/Maybe_String" } ] }, "not": { "description": "A single sub-rule and matches a node if the sub rule does not match.", "allOf": [ { "$ref": "#/definitions/Maybe_SerializableRule" } ] }, "nthChild": { "description": "`nth_child` accepts number, string or object. It specifies the position in nodes' sibling list.", "allOf": [ { "$ref": "#/definitions/Maybe_SerializableNthChild" } ] }, "pattern": { "description": "A pattern string or a pattern object.", "allOf": [ { "$ref": "#/definitions/Maybe_PatternStyle" } ] }, "precedes": { "description": "`precedes` accepts a relational rule object. the target node must appear before another node matching the `precedes` sub-rule.", "allOf": [ { "$ref": "#/definitions/Maybe_Relation" } ] }, "range": { "description": "`range` accepts a range object. the target node must exactly appear in the range.", "allOf": [ { "$ref": "#/definitions/Maybe_SerializableRange" } ] }, "regex": { "description": "A Rust regular expression to match the node's text. https://docs.rs/regex/latest/regex/#syntax", "allOf": [ { "$ref": "#/definitions/Maybe_String" } ] } }, "additionalProperties": false }, "SerializableStopBy": { "oneOf": [ { "type": "string", "enum": [ "neighbor", "end" ] }, { "$ref": "#/definitions/SerializableRule" } ] }, "Severity": { "oneOf": [ { "description": "A kind reminder for code with potential improvement.", "type": "string", "enum": [ "hint" ] }, { "description": "A suggestion that code can be improved or optimized.", "type": "string", "enum": [ "info" ] }, { "description": "A warning that code might produce bugs or does not follow best practice.", "type": "string", "enum": [ "warning" ] }, { "description": "An error that code produces bugs or has logic errors.", "type": "string", "enum": [ "error" ] }, { "description": "Turns off the rule.", "type": "string", "enum": [ "off" ] } ] }, "Strictness": { "oneOf": [ { "description": "all nodes are matched", "type": "string", "enum": [ "cst" ] }, { "description": "all nodes except source trivial nodes are matched.", "type": "string", "enum": [ "smart" ] }, { "description": "only ast nodes are matched", "type": "string", "enum": [ "ast" ] }, { "description": "ast-nodes excluding comments are matched", "type": "string", "enum": [ "relaxed" ] }, { "description": "ast-nodes excluding comments, without text", "type": "string", "enum": [ "signature" ] } ] }, "StringCase": { "description": "An enumeration representing different cases for strings.", "type": "string", "enum": [ "lowerCase", "upperCase", "capitalize", "camelCase", "snakeCase", "kebabCase", "pascalCase" ] }, "Substring_for_String": { "description": "Extracts a substring from the meta variable's text content.\n\nBoth `start_char` and `end_char` support negative indexing, which counts character from the end of an array, moving backwards.", "type": "object", "required": [ "source" ], "properties": { "endChar": { "description": "optional ending character index of the substring, defaults to the end of the string.", "type": [ "integer", "null" ], "format": "int32" }, "source": { "description": "source meta variable to be transformed", "type": "string" }, "startChar": { "description": "optional starting character index of the substring, defaults to 0.", "type": [ "integer", "null" ], "format": "int32" } } }, "Transformation_for_String": { "description": "Represents a transformation that can be applied to a matched AST node. Available transformations are `substring`, `replace` and `convert`.", "oneOf": [ { "type": "object", "required": [ "substring" ], "properties": { "substring": { "$ref": "#/definitions/Substring_for_String" } }, "additionalProperties": false }, { "type": "object", "required": [ "replace" ], "properties": { "replace": { "$ref": "#/definitions/Replace_for_String" } }, "additionalProperties": false }, { "type": "object", "required": [ "convert" ], "properties": { "convert": { "$ref": "#/definitions/Convert_for_String" } }, "additionalProperties": false }, { "type": "object", "required": [ "rewrite" ], "properties": { "rewrite": { "$ref": "#/definitions/Rewrite_for_String" } }, "additionalProperties": false } ] } } }