Skip to content

@vltpkg/dss-parser parse() accepts semantically invalid DSS instead of throwing #1680

Description

@usrrname

What to build

parse() from @vltpkg/dss-parser is meant to reject invalid Dependency Selector Syntax. Currently, it only throws on malformed syntax (unbalanced brackets/parens) — and even then via a generic TypeError: Cannot read properties of undefined, not a validation error.

Semantically invalid selectors (unknown pseudo-classes, nonsense tag words, empty strings, dangling combinators) parse without complaint.

Expected behaviour

parse() should throw a clear, typed validation error when given DSS that could never be a valid selector — unknown pseudo-classes/combinators, empty/whitespace-only input, and dangling combinators — so callers can trust it as a validation gate.

How this surfaced

Found while reviewing the eval harness for the dss-query skill (src/query/skills/dss-query/evals/run.ts) in #1678 for the dss-query agent skill.

The harness grades generated selectors by running them through parse() on the assumption — stated in its header comment and README — that @vltpkg/dss-parser "throws on invalid DSS." Probing the parser directly showed that assumption is false: its "selector validity" check is effectively a no-op for anything short of unbalanced brackets. The harness docs have been softened on the jc/dss-skill branch to describe the real (lenient) behavior; this issue tracks fixing the parser so that check can be strict again.

Reproduction

Run from the repo root (resolves the workspace package):

node --input-type=module -e "
import('@vltpkg/dss-parser').then(m => {
  for (const t of [':fake-pseudo', 'not a selector at all', '> >', '', '   ', ':::bogus<<']) {
    try { m.parse(t); console.log('NO THROW |', JSON.stringify(t)) }
    catch { console.log('throws   |', JSON.stringify(t)) }
  }
})"

Actual output — every case prints NO THROW:

NO THROW | ":fake-pseudo"
NO THROW | "not a selector at all"
NO THROW | "> >"
NO THROW | ""
NO THROW | "   "
NO THROW | ":::bogus<<"

Meanwhile parse(':outdated(') and parse('[name=') throw Cannot read properties of undefined — a crash, not a validation error.

Acceptance criteria

  • parse() throws a typed/descriptive error for unknown pseudo-classes (e.g. :fake-pseudo)
  • parse() throws for empty / whitespace-only input and dangling combinators (> >, :root >)
  • Malformed bracket/paren input (:outdated(, [name=) throws a descriptive validation error rather than a generic TypeError
  • The set of recognized pseudo-classes/combinators is validated against DSS's actual grammar
  • Tests cover valid selectors (no throw) and each invalid category above
  • The dss-query eval harness comment/README are updated to note that parse() now validates semantically

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugsomething isn't workingqueryanything related to query or the dependency selector syntax

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions