{"record":{"id":"84b3d3ae46d3f1df","repo":"denoland/deno","slug":"unknown-pseudo-selector-lex-value","errorCode":null,"errorMessage":"Unknown pseudo selector: '${lex.value}'","messagePattern":"Unknown pseudo selector: '(.+?)'","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/js/40_lint_selector.js","lineNumber":725,"sourceCode":"          stack.push([]);\n\n          continue;\n        }\n        case \"not\": {\n          lex.next();\n          lex.expect(Token.BraceOpen);\n          lex.next();\n\n          current.push({\n            type: PSEUDO_NOT,\n            selectors: [],\n          });\n          stack.push([]);\n\n          continue;\n        }\n        default:\n          throw new Error(`Unknown pseudo selector: '${lex.value}'`);\n      }\n    } else if (lex.token === Token.Comma) {\n      if (throwOnComma) {\n        throw new Error(`Multiple selector arguments not supported here`);\n      }\n\n      lex.next();\n      if (lex.token === Token.Space) {\n        lex.next();\n      }\n\n      popSelector(result, stack);\n      stack.push([]);\n      continue;\n    } else if (lex.token === Token.BraceClose) {\n      throwOnComma = false;\n      popSelector(result, stack);\n    } else if (lex.token === Token.Op) {","sourceCodeStart":707,"sourceCodeEnd":743,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/cli/js/40_lint_selector.js#L707-L743","documentation":"Thrown by the pseudo-selector switch default (cli/js/40_lint_selector.js) when a ':' pseudo-class is encountered that this parser does not implement. It recognizes a fixed set (including :not(), :has(), :is(), :nth-child()); anything else — with or without arguments — hits the default and throws with the offending name.","triggerScenarios":"Visitor-key selectors using unsupported pseudos: \":matches(X)\", \":root\", \":first-of-type\", \":empty\", \":statement\" — any ':' word not in the supported set. Note :not() takes brace-enclosed arguments here, and unsupported pseudos throw even if they are valid CSS or esquery.","commonSituations":"Copying a selector from esquery documentation assuming full parity; using CSS structural pseudos (:first-child variants beyond what's supported) on AST nodes; typos like ':hass(...)' or ':nota(...)' that fall through to the default.","solutions":["Replace the unsupported pseudo with the equivalent supported construct (:matches → :is)","Express structural conditions inside the visitor callback (track child index yourself) when no pseudo exists","Check the exact pseudo name for typos against the supported list"],"exampleFix":"// before\n\":matches(CallExpression, NewExpression)\"(node) {},\n\n// after\n\":is(CallExpression, NewExpression)\"(node) {},","handlingStrategy":"validation","validationCode":"const SUPPORTED_PSEUDOS = new Set([\"has\", \"is\", \"not\", \"nth-child\" /* + first/last-child if used */]);\nfunction checkPseudos(sel) {\n  for (const m of sel.matchAll(/:([a-zA-Z-]+)/g)) {\n    if (!SUPPORTED_PSEUDOS.has(m[1])) {\n      throw new Error(`unsupported pseudo ':${m[1]}' in '${sel}'`);\n    }\n  }\n}","typeGuard":"function usesSupportedPseudos(sel) {\n  return [...sel.matchAll(/:([a-zA-Z-]+)/g)].every((m) =>\n    SUPPORTED_PSEUDOS.has(m[1])\n  );\n}","tryCatchPattern":null,"preventionTips":["Translate from other dialects explicitly: :matches → :is; positional pseudos → visitor-side index tracking","Keep a cheat sheet of supported pseudos next to your plugin rules"],"tags":["lint","selector","pseudo-class","esquery","parser"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}