{
  "version": "v1",
  "timestamp": 1776539423236,
  "ruleHash": "e3b0c44298fc1c14",
  "queries": [
    {
      "id": "await-in-loop",
      "name": "Await in Loop",
      "severity": "warning",
      "language": "typescript",
      "message": "Await in loop — sequential execution is slow, use Promise.all()",
      "query": "  (for_in_statement\n    body: (statement_block\n      (expression_statement\n        (await_expression) @AWAIT)))\n  (for_statement\n    body: (statement_block\n      (expression_statement\n        (await_expression) @AWAIT)))\n  (while_statement\n    body: (statement_block\n      (expression_statement\n        (await_expression) @AWAIT)))",
      "metavars": [
        "AWAIT"
      ],
      "defect_class": "injection",
      "inline_tier": "blocking"
    },
    {
      "id": "console-statement",
      "name": "Console Statement",
      "severity": "warning",
      "language": "typescript",
      "message": "{{METHOD}} — remove debug statements before committing",
      "query": "  (call_expression\n    function: (member_expression\n      object: (identifier) @OBJ (#eq? @OBJ \"console\")\n      property: (property_identifier) @METHOD (#not-eq? @METHOD \"dbg\"))\n    arguments: (arguments) @ARGS)\n\n# Skip matches inside test blocks — no-console-in-tests handles that case",
      "metavars": [
        "OBJ",
        "METHOD",
        "ARGS"
      ],
      "post_filter": "not_in_test_block",
      "defect_class": "safety",
      "inline_tier": "warning"
    },
    {
      "id": "constructor-super",
      "name": "Missing super() call in derived class constructor",
      "severity": "error",
      "language": "typescript",
      "message": "Constructor of derived class must call super() before accessing 'this'",
      "query": "  (class_declaration\n    (class_heritage\n      (extends_clause) @EXTENDS)\n    body: (class_body\n      (method_definition\n        name: (property_identifier) @CONSTRUCTOR\n        (#eq? @CONSTRUCTOR \"constructor\")\n        body: (statement_block) @BODY)))",
      "metavars": [
        "EXTENDS",
        "CONSTRUCTOR",
        "BODY"
      ],
      "post_filter": "no_super_call",
      "post_filter_params": "{}",
      "defect_class": "correctness",
      "inline_tier": "blocking"
    },
    {
      "id": "debugger-statement",
      "name": "Debugger Statement",
      "severity": "error",
      "language": "typescript",
      "message": "Debugger statement — remove before committing",
      "query": "  (debugger_statement) @DEBUGGER",
      "metavars": [
        "DEBUGGER"
      ],
      "defect_class": "safety",
      "inline_tier": "blocking"
    },
    {
      "id": "deep-nesting",
      "name": "Deep Nesting",
      "severity": "warning",
      "language": "typescript",
      "message": "Deep nesting (3+ levels) — consider early returns or extract functions",
      "query": "  [\n    ;; Pattern 1: if inside if inside if\n    (statement_block\n      (if_statement\n        consequence: (statement_block\n          (if_statement\n            consequence: (statement_block\n              (if_statement) @IF_NESTED)))))\n\n    ;; Pattern 2: for inside if inside if\n    (statement_block\n      (if_statement\n        consequence: (statement_block\n          (if_statement\n            consequence: (statement_block\n              (for_statement) @FOR_NESTED)))))\n\n    ;; Pattern 3: while inside if inside if\n    (statement_block\n      (if_statement\n        consequence: (statement_block\n          (if_statement\n            consequence: (statement_block\n              (while_statement) @WHILE_NESTED)))))\n\n    ;; Pattern 4: try inside if inside if\n    (statement_block\n      (if_statement\n        consequence: (statement_block\n          (if_statement\n            consequence: (statement_block\n              (try_statement) @TRY_NESTED)))))\n\n    ;; Pattern 5: if inside for inside if\n    (statement_block\n      (if_statement\n        consequence: (statement_block\n          (for_statement\n            body: (statement_block\n              (if_statement) @IF_IN_FOR)))))\n\n    ;; Pattern 6: if inside while inside if\n    (statement_block\n      (if_statement\n        consequence: (statement_block\n          (while_statement\n            body: (statement_block\n              (if_statement) @IF_IN_WHILE)))))\n\n    ;; Pattern 7: for inside for inside for\n    (statement_block\n      (for_statement\n        body: (statement_block\n          (for_statement\n            body: (statement_block\n              (for_statement) @FOR_NESTED)))))\n  ]",
      "metavars": [
        "IF_NESTED",
        "FOR_NESTED",
        "WHILE_NESTED",
        "TRY_NESTED",
        "IF_IN_FOR",
        "IF_IN_WHILE"
      ],
      "defect_class": "safety",
      "inline_tier": "review"
    },
    {
      "id": "deep-promise-chain",
      "name": "Deep Promise Chain (4+ levels)",
      "severity": "warning",
      "language": "typescript",
      "message": "Promise chain {{M1}} → {{M2}} → {{M3}} → {{M4}} — consider async/await",
      "query": "  (call_expression\n    function: (member_expression\n      object: (call_expression\n        function: (member_expression\n          object: (call_expression\n            function: (member_expression\n              object: (call_expression\n                function: (member_expression\n                  property: (property_identifier) @M1)\n                arguments: (arguments))\n              property: (property_identifier) @M2)\n            arguments: (arguments))\n          property: (property_identifier) @M3)\n        arguments: (arguments))\n      property: (property_identifier) @M4)\n    arguments: (arguments))\n  (#match? @M1 \"^(then|catch|finally)$\")\n  (#match? @M2 \"^(then|catch|finally)$\")\n  (#match? @M3 \"^(then|catch|finally)$\")\n  (#match? @M4 \"^(then|catch|finally)$\")",
      "metavars": [
        "M1",
        "M2",
        "M3",
        "M4"
      ],
      "defect_class": "async-misuse",
      "inline_tier": "warning"
    },
    {
      "id": "empty-catch",
      "name": "Empty Catch Block",
      "severity": "error",
      "language": "typescript",
      "message": "Empty catch block — properly handle or log the error",
      "query": "  (catch_clause\n    (identifier) @ERR\n    (statement_block) @BODY)\n\n# Post-filter: Check if body is effectively empty (ignoring comments)",
      "metavars": [
        "ERR",
        "BODY"
      ],
      "post_filter": "empty_body",
      "defect_class": "silent-error",
      "inline_tier": "blocking"
    },
    {
      "id": "no-eval",
      "name": "Eval Usage",
      "severity": "error",
      "language": "typescript",
      "message": "eval() detected — security risk, never use eval",
      "query": "  (call_expression\n    function: (identifier) @FUNC\n    (#eq? @FUNC \"eval\")\n    arguments: (arguments) @ARGS)",
      "metavars": [
        "FUNC",
        "ARGS"
      ],
      "defect_class": "injection",
      "inline_tier": "blocking"
    },
    {
      "id": "hardcoded-secrets",
      "name": "Hardcoded Secret",
      "severity": "error",
      "language": "typescript",
      "message": "Hardcoded secret in variable assignment — use environment variables",
      "query": "  [\n    (lexical_declaration\n      (variable_declarator\n        name: (identifier) @VARNAME\n        value: (string)))\n    (expression_statement\n      (assignment_expression\n        left: (identifier) @VARNAME\n        right: (string)))\n  ]",
      "metavars": [
        "VARNAME"
      ],
      "post_filter": "check_secret_pattern",
      "defect_class": "secrets",
      "inline_tier": "blocking"
    },
    {
      "id": "long-parameter-list",
      "name": "Long Parameter List",
      "severity": "warning",
      "language": "typescript",
      "message": "Function has {{PARAM_COUNT}} parameters — use object pattern",
      "query": "  (function_declaration\n    name: (identifier) @NAME\n    parameters: (formal_parameters) @PARAMS\n    body: (statement_block) @BODY)",
      "metavars": [
        "NAME",
        "PARAMS",
        "BODY"
      ],
      "post_filter": "count_params",
      "post_filter_params": "",
      "defect_class": "safety",
      "inline_tier": "review"
    },
    {
      "id": "mixed-async-styles",
      "name": "Mixed Async/Await and Promise Chains",
      "severity": "warning",
      "language": "typescript",
      "message": "Mixed async/await + promise chains — use consistent async style",
      "query": "  (function_declaration\n    (async_modifier)\n    body: (statement_block) @BODY)\n\n# Post-filter: Check if body contains both await and .then()",
      "metavars": [
        "BODY"
      ],
      "post_filter": "has_mixed_async",
      "defect_class": "async-misuse",
      "inline_tier": "warning"
    },
    {
      "id": "nested-ternary",
      "name": "Nested Ternary",
      "severity": "warning",
      "language": "typescript",
      "message": "Nested ternary — use if/else or early returns for clarity",
      "query": "  (ternary_expression\n    consequence: (ternary_expression) @NESTED)\n  (ternary_expression\n    alternative: (ternary_expression) @NESTED)",
      "metavars": [
        "NESTED"
      ],
      "defect_class": "safety",
      "inline_tier": "review"
    },
    {
      "id": "no-console-in-tests",
      "name": "Console Statement in Test",
      "severity": "warning",
      "language": "typescript",
      "message": "console.{{METHOD}} in test block — use proper assertions or logging",
      "query": "  (call_expression\n    function: (member_expression\n      object: (identifier) @OBJ (#eq? @OBJ \"console\")\n      property: (property_identifier) @METHOD)\n    arguments: (arguments) @ARGS)",
      "metavars": [
        "OBJ",
        "METHOD",
        "ARGS"
      ],
      "post_filter": "in_test_block",
      "defect_class": "safety",
      "inline_tier": "warning"
    },
    {
      "id": "no-dupe-class-members",
      "name": "Duplicate class member",
      "severity": "error",
      "language": "typescript",
      "message": "Duplicate class member '$NAME' - previous declaration will be overwritten",
      "query": "  (class_body\n    (method_definition\n      name: (property_identifier) @NAME1\n      (#match? @NAME1 \"^[^#]\"))\n    (method_definition\n      name: (property_identifier) @NAME2\n      (#eq? @NAME1 @NAME2)))",
      "metavars": [
        "NAME1",
        "NAME2"
      ],
      "defect_class": "correctness",
      "inline_tier": "blocking"
    },
    {
      "id": "sql-injection",
      "name": "SQL Injection Risk",
      "severity": "error",
      "language": "typescript",
      "message": "SQL injection risk — use parameterized queries, never interpolate into SQL",
      "query": "  (call_expression\n    function: [\n      (identifier) @SQL_FUNC\n      (member_expression property: (property_identifier) @SQL_FUNC)\n    ]\n    arguments: (arguments\n      (template_string (template_substitution) @INTERPOLATION))\n    (#match? @SQL_FUNC \"^(query|execute|exec|run)$\"))",
      "metavars": [
        "SQL_FUNC",
        "INTERPOLATION"
      ],
      "defect_class": "injection",
      "inline_tier": "blocking"
    },
    {
      "id": "ts-command-injection",
      "name": "Command Injection Sink",
      "severity": "warning",
      "language": "typescript",
      "message": "Potential command injection sink — avoid child_process command execution with untrusted input",
      "query": "  [\n    (call_expression\n      function: (member_expression\n        object: (identifier) @MOD\n        property: (property_identifier) @FN)\n      arguments: (arguments) @ARGS)\n    (call_expression\n      function: (member_expression\n        object: (member_expression\n          object: (identifier) @MOD\n          property: (property_identifier) @NS)\n        property: (property_identifier) @FN)\n      arguments: (arguments) @ARGS)\n  ]\n  (#eq? @MOD \"child_process\")\n  (#match? @FN \"^(exec|execSync)$\")",
      "metavars": [
        "MOD",
        "NS",
        "FN",
        "ARGS"
      ],
      "post_filter": "ts_command_injection_sink",
      "defect_class": "injection",
      "inline_tier": "warning"
    },
    {
      "id": "ts-detached-async-call",
      "name": "Detached Async Call",
      "severity": "warning",
      "language": "typescript",
      "message": "Detached async call — ensure this Promise is awaited or explicitly handled",
      "query": "  (expression_statement\n    (call_expression\n      function: [\n        (identifier) @FN\n        (member_expression\n          property: (property_identifier) @FN)\n      ]\n      arguments: (arguments) @ARGS))\n  (#match? @FN \"(Async$|fetch$|request$)\")",
      "metavars": [
        "FN",
        "ARGS"
      ],
      "post_filter": "ts_detached_async_call",
      "defect_class": "async-misuse",
      "inline_tier": "warning"
    },
    {
      "id": "ts-insecure-random",
      "name": "Insecure Randomness",
      "severity": "warning",
      "language": "typescript",
      "message": "Insecure randomness source detected — use crypto.getRandomValues or secure RNG APIs",
      "query": "  (call_expression\n    function: (member_expression\n      object: (identifier) @OBJ\n      property: (property_identifier) @FN)\n    arguments: (arguments) @ARGS)\n  (#eq? @OBJ \"Math\")\n  (#eq? @FN \"random\")",
      "metavars": [
        "OBJ",
        "FN",
        "ARGS"
      ],
      "post_filter": "ts_insecure_random_source",
      "defect_class": "injection",
      "inline_tier": "warning"
    },
    {
      "id": "ts-ssrf",
      "name": "SSRF Risk",
      "severity": "warning",
      "language": "typescript",
      "message": "Potential SSRF sink — validate and allowlist outbound URLs",
      "query": "  [\n    (call_expression\n      function: (identifier) @FN\n      arguments: (arguments [(identifier) (member_expression) (call_expression)] @URL))\n    (call_expression\n      function: (member_expression\n        object: (identifier) @OBJ\n        property: (property_identifier) @FN)\n      arguments: (arguments [(identifier) (member_expression) (call_expression)] @URL))\n  ]\n  (#match? @FN \"^(fetch|get|post|put|patch|delete|request)$\")",
      "metavars": [
        "OBJ",
        "FN",
        "URL"
      ],
      "post_filter": "ts_ssrf_sink",
      "defect_class": "injection",
      "inline_tier": "warning"
    },
    {
      "id": "ts-weak-hash",
      "name": "Weak Hash Primitive",
      "severity": "warning",
      "language": "typescript",
      "message": "Weak hash primitive selected (md5/sha1) — use sha256+ for security-sensitive contexts",
      "query": "  (call_expression\n    function: (member_expression\n      property: (property_identifier) @FN)\n    arguments: (arguments\n      (string (string_fragment) @ALG)\n      (_)*))\n  (#eq? @FN \"createHash\")\n  (#match? @ALG \"^(md5|sha1)$\")",
      "metavars": [
        "FN",
        "ALG"
      ],
      "post_filter": "ts_weak_hash_algorithm",
      "defect_class": "injection",
      "inline_tier": "warning"
    },
    {
      "id": "unsafe-regex",
      "name": "Dynamic Regex Construction",
      "severity": "error",
      "language": "typescript",
      "message": "Dynamic regex from user input — can cause ReDoS (Regular Expression Denial of Service)",
      "query": "  (new_expression\n    constructor: (identifier) @CTOR\n    (#eq? @CTOR \"RegExp\")\n    arguments: (arguments\n      (template_string\n        (template_substitution) @INTERPOLATION) @PATTERN))",
      "metavars": [
        "CTOR",
        "INTERPOLATION",
        "PATTERN"
      ],
      "defect_class": "injection",
      "inline_tier": "blocking"
    },
    {
      "id": "variable-shadowing",
      "name": "Variable Shadowing",
      "severity": "warning",
      "language": "typescript",
      "message": "Variable '{{NAME}}' shadows a parameter — use a distinct name",
      "query": "  (function_declaration\n    parameters: (formal_parameters\n      (required_parameter\n        pattern: (identifier) @PARAM))\n    body: (statement_block\n      (lexical_declaration\n        (variable_declarator\n          name: (identifier) @NAME))))",
      "metavars": [
        "PARAM",
        "NAME"
      ],
      "post_filter": "name_matches_param",
      "defect_class": "safety",
      "inline_tier": "review"
    }
  ]
}