{"record":{"id":"6369f32e2fc043c1","repo":"denoland/deno","slug":"invalid-regexp-pattern-raw","errorCode":null,"errorMessage":"Invalid RegExp pattern: ${raw}","messagePattern":"Invalid RegExp pattern: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/js/40_lint_selector.js","lineNumber":406,"sourceCode":"  switch (raw) {\n    case \"true\":\n      return true;\n    case \"false\":\n      return false;\n    case \"null\":\n      return null;\n    case \"undefined\":\n      return undefined;\n    default:\n      if (raw.startsWith(\"'\") && raw.endsWith(\"'\")) {\n        if (raw.length === 2) return \"\";\n        return raw.slice(1, -1);\n      } else if (raw.startsWith('\"') && raw.endsWith('\"')) {\n        if (raw.length === 2) return \"\";\n        return raw.slice(1, -1);\n      } else if (raw.startsWith(\"/\")) {\n        const end = raw.lastIndexOf(\"/\");\n        if (end === -1) throw new Error(`Invalid RegExp pattern: ${raw}`);\n        const pattern = raw.slice(1, end);\n        const flags = end < raw.length - 1 ? raw.slice(end + 1) : undefined;\n        return new RegExp(pattern, flags);\n      } else if (NUMBER_REG.test(raw)) {\n        return Number(raw);\n      } else if (BIGINT_REG.test(raw)) {\n        return BigInt(raw.slice(0, -1));\n      }\n\n      return raw;\n  }\n}\n\nexport const ELEM_NODE = 1;\nexport const RELATION_NODE = 2;\nexport const ATTR_EXISTS_NODE = 3;\nexport const ATTR_BIN_NODE = 4;\nexport const PSEUDO_NTH_CHILD = 5;","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/js/40_lint_selector.js#L388-L424","documentation":"Attribute values in lint selectors may be regex literals written /pattern/flags (e.g. [id.name=/^_foo$/]). getFromRawValue in cli/js/40_lint_selector.js splits the raw token on the last '/' to separate pattern from flags and throws `Invalid RegExp pattern: <raw>` when it cannot find a closing slash. Note that as written the -1 check cannot fire while the value starts with '/', so in practice an unterminated regex like [id.name=/_foo] more often surfaces as a RegExp constructor SyntaxError (garbage parsed as flags) — same root cause: the regex literal is not properly delimited.","triggerScenarios":"A visitor key with a regex attribute value missing the closing slash: \"Declarator[id.name=/_temp]\", or a value that begins with '/' but is never closed, so the parser cannot split pattern and flags.","commonSituations":"Writing [id.name=/_foo] and forgetting the trailing slash; editing a key and deleting the delimiter; assuming bare '/foo' works like a contains-match.","solutions":["Close the regex literal: [id.name=/_foo] → [id.name=/_foo/] (optionally anchored: /^_foo$/).","If you meant a literal string match, use quoting instead: [id.name=\"_foo\"].","If you see a RegExp SyntaxError about flags on the same key, check for the same missing-slash problem."],"exampleFix":"// before\n\"Declarator[id.name=/_temp]\"(node) { /* ... */ },\n\n// after\n\"Declarator[id.name=/^_temp$/]\"(node) { /* ... */ },","handlingStrategy":"validation","validationCode":"function checkRegexAttrs(key) {\n  for (const m of key.matchAll(/\\[([^=\\]]+)=([^\\]]*)\\]/g)) {\n    const raw = m[2];\n    if (raw.startsWith(\"/\") && !/\\/.+\\/[a-z]*$/.test(raw)) {\n      throw new Error(`Unterminated regex value in \"${key}\": ${raw}`);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always delimit regex attribute values with both slashes: [id.name=/_foo/].","Anchor when you mean exact matches: [id.name=/^_foo$/].","For literal string matching use quotes instead of slashes: [id.name=\"foo\"]."],"tags":["deno","deno-lint","lint-plugin","selector","regex","parse-error"],"backgroundTag":"invalid-selector-syntax","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}