Skip to content

fix(lint): block on digit-leading ids instead of only warning - #3980

Open
miga-heygen wants to merge 1 commit into
mainfrom
fix-digit-leading-id-css-escape
Open

miga-heygen wants to merge 1 commit into
mainfrom
fix-digit-leading-id-css-escape

Conversation

@miga-heygen

Copy link
Copy Markdown
Contributor

Summary

An element id that starts with a digit (e.g. id="1-hook") breaks any bare CSS id selector built from it — #1-hook throws a SyntaxError in querySelector(). In a composition's inline <script>, this typically happens through a GSAP string selector (tl.fromTo("#1-hook", ...)), and the thrown error silently aborts the rest of that <script> block. The referenced element never gets its animation registered — it just sits frozen at its template-initial position — while the render itself completes and reports success, with no visible error anywhere.

id_requires_css_escape already detects this correctly (any id matching /^\d/), but it was "warning" severity, which both hyperframes render and hyperframes check treat as non-blocking by default.

Fix

Promote id_requires_css_escape to "error" severity. hyperframes check already treats "error"-severity findings as unconditionally blocking (regardless of --strict), so this makes a digit-leading id fail the standard pre-render gate loudly instead of shipping a silently-frozen composition. hyperframes render itself is unaffected by default — it only blocks on errors under --strict, same as before.

Test plan

  • Updated the existing unit test's severity expectation ("warning""error").
  • Ran the full packages/lint suite (excluding 4 files that fail to load in this sandbox for an unrelated, pre-existing node:path/posix interop reason, confirmed not reproducible elsewhere): 606/606 passing, including core.test.ts at 77/77.
  • Adversarial review confirmed: hyperframes check's call site hardcodes strict-errors unconditionally, so this change has the intended effect; hyperframes render's default (lenient) behavior is untouched; no other file assumes this rule is warning-tier; no existing test fixture repo-wide contains a digit-leading id that would newly break; nothing else needs a companion update.
  • tsc --noEmit, oxlint, oxfmt --check clean on both touched files.

A digit-leading id (e.g. id="1-hook") breaks any bare `#1-hook` CSS
selector with a SyntaxError, including inline GSAP string selectors
like tl.fromTo("#1-hook", ...). That throw silently aborts the rest of
the <script> block that built the selector, so the referenced element
never animates — but the render itself still reports success, and the
freeze has no visible error anywhere.

id_requires_css_escape already detects this correctly; it was only
"warning" severity, which hyperframes render and hyperframes check
both treat as non-blocking by default. Promote it to "error" so
`hyperframes check` (which always treats errors as blocking) catches
this unconditionally instead of only under --strict.
Co-Authored-By: Miguel Ángel <miguel.sierra@heygen.com>

@somanshreddy somanshreddy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE at b378ec18 — correct one-line severity promotion; I verified the mechanism and the blast radius. Independent manual pass (codex disabled per workspace cap — my own source verification, flagged for honesty).

The promotion actually changes gating — I traced it to the exit-code math. hyperframes check computes ok in checkPipeline.ts:

ok: errorCount === 0 && (!options.strict || warningCount === 0)

and checkExitCode(report) = report.ok ? 0 : 1. So an error-severity finding forces ok=false → exit 1 unconditionally, whereas a warning only fails the gate under --strict. Moving id_requires_css_escape from warningerror therefore makes a digit-leading id block the standard pre-render check loudly, exactly as the PR claims — and hyperframes render's default lenient behavior (blocks only on --strict) is untouched, since it's the same severity plumbing.

The detection is unchanged and correct. The rule still fires on /^\d/ ids; only severity and the message string changed. #1-hook genuinely throws SyntaxError in querySelector(), and inside an inline GSAP string selector that aborts the rest of the <script> silently while the render still reports success — a real "succeeds but frozen" failure that warrants blocking.

Blast radius checked, not assumed. I scanned every template/fixture/scaffold/example/starter .html at head for a digit-leading id (id="[0-9]…") — zero hits. So no shipped template or check-tested fixture newly fails the gate. CI green corroborates: every tested fixture still passes, and Lint/Build/CLI-smoke are green. The rule already existed at warning tier, so any pre-existing digit-leading id would already have surfaced as a finding.

Test is meaningful. core.test.ts flips the expectation warningerror and still pins elementId and the CSS.escape fixHint, so it fails if the rule stops firing or mislabels the element — not just an echo of the severity string.

BLOCKED is branch protection awaiting this stamp, not a red check. Nothing to hold on — Home to merge.

Provenance: my own source pass at b378ec18 (core.ts, core.test.ts, check.ts, checkPipeline.ts) + template/fixture digit-id scan; codex disabled (owner cap). Did not run the suite locally (env); resting on source verification + the stated 606/606 run + green required checks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants