denoland/deno · error · Error

Unknown attribute operator: '${s}'

Error message

Unknown attribute operator: '${s}'

What it means

Thrown by the attribute-operator lookup in the esquery-style selector parser (cli/js/40_lint_selector.js) when a selector uses an operator inside [...] that is not one of the supported ones (=, !=, <, <=, >, >=, ~, +). Lint rule visitor keys are parsed as selectors, so an unsupported operator aborts selector compilation.

Source

Thrown at cli/js/40_lint_selector.js:113

  switch (s) {
    case "=":
      return BinOp.Equal;
    case "!=":
      return BinOp.NotEqual;
    case ">":
      return BinOp.Greater;
    case ">=":
      return BinOp.GreaterThan;
    case "<":
      return BinOp.Less;
    case "<=":
      return BinOp.LessThan;
    case "~":
      return BinOp.Tilde;
    case "+":
      return BinOp.Plus;
    default:
      throw new Error(`Unknown attribute operator: '${s}'`);
  }
}

export class Lexer {
  token = Token.Word;
  start = 0;
  end = 0;
  ch = 0;
  i = -1;

  value = "";

  /**
   * @param {string} input
   */
  constructor(input) {
    this.input = input;
    this.step();

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Replace the unsupported operator with a supported one, or move the matching logic into the visitor callback
  2. For substring tests, use a regex value with a supported operator, e.g. [name=/foo/] where supported, or filter in code

Example fix

// before
"ObjectExpression[properties.length > 0][key ^= \"data\"]"(node) {},

// after
"ObjectExpression[properties.length > 0]"(node) {
  // do the key-prefix test in the visitor body
},
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED_ATTR_OPS = new Set(["=", "!=", "<", "<=", ">", ">=", "~", "+"]);
function checkAttrOps(selector) {
  for (const m of selector.matchAll(/\[([^\]]+)\]/g)) {
    const op = m[1].match(/(?:!=|=|<=|>=|<|>|~|\+|[^\s=<>~+]+)/)?.[0];
    if (op && !SUPPORTED_ATTR_OPS.has(op)) {
      throw new Error(`unsupported attribute operator '${op}' in '${selector}'`);
    }
  }
}

Type guard

function usesOnlySupportedAttrOps(selector) {
  return ![...selector.matchAll(/[!=<>~^$*]+=/g)].some((m) =>
    !["!=", "<=", ">="].includes(m[0])
  );
}

Prevention

When it happens

Trigger: A visitor key / selector like "VariableDeclaration[kind ^= \"const\"]", "[name %= \"x\"]", or "[a $= \"b\"]" — substring/caret/dollar regex-style operators from other selector dialects are not implemented.

Common situations: Copying an attribute selector syntax from CSS attribute selectors or another AST query tool into a Deno lint plugin rule; assuming esquery's full operator set is supported when this parser implements a subset.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/2cc75f1e2797ce04. Report an issue: GitHub.