Skip to content

v0.9.3

Choose a tag to compare

@reteps reteps released this 23 Apr 14:39
· 61 commits to master since this release
17b86c4

Fix: multi-segment :not() in custom lint rules

:not(...) with a combinator inside it was silently dropped by the selector engine. Given a rule like:

{
  "id": "require-img-class-or-style",
  "selector": "img:not([style]):not([class]):not(pl-overlay img)",
  "message": "Annotate <img> or keep it under <pl-overlay>."
}

the third negation (:not(pl-overlay img)) was ignored because checkSelfNegations bailed on any alternative with more than one segment. Only simple compound selectors on the element itself worked inside :not().

What works now

:not(X) accepts any multi-segment selector, tested against the node's ancestor/sibling context (matching Element.matches semantics):

  • img:not(pl-overlay img) — descendant
  • td:not(thead > td) — direct child
  • p:not(h2 + p) — adjacent sibling
  • button:not({{#admin}} button) — crosses into a Mustache section
  • section:has(img:not(pl-overlay img)) — composes inside :has()

Simple forms (:not(div), :not([attr]), :not(.cls), :not(:has(...))) are unchanged.

Scope

Affects the selector matcher shared by the CLI (htmlmustache check), the LSP/VS Code extension, and the browser API.