Skip to content

fix(capture): drop *-prefixed attributes to keep XMLSerializer output well-formed - #445

Merged
tinchox5 merged 1 commit into
zumerlab:mainfrom
venkateshwarreddyr:fix/star-prefixed-attributes
Jul 3, 2026
Merged

fix(capture): drop *-prefixed attributes to keep XMLSerializer output well-formed#445
tinchox5 merged 1 commit into
zumerlab:mainfrom
venkateshwarreddyr:fix/star-prefixed-attributes

Conversation

@venkateshwarreddyr

@venkateshwarreddyr venkateshwarreddyr commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #446.

HTML attribute names beginning with * (e.g. Angular structural directives like *ngIf, *ngFor, or any custom *data-foo) are valid in HTML5 but illegal in XML — * is not a NameStartChar. They survive cloning, get serialized by XMLSerializer.serializeToString into <foreignObject>, and the resulting data: URL is malformed. img.decode() then throws EncodingError: The source image cannot be decoded..

Problem

sanitizeAttributesForXHTML already strips attribute names that would break the XHTML serializer:

  • @ — never valid in XML
  • unknown : prefixes (only xml / xlink allowed)
  • framework directives (x-*, v-*, :, on:*, bind:*, let:*, class:*)

* is another NameStartChar violation but was missing from that pass. Browsers don't enforce XML rules on serialization, so this only blows up downstream at img.decode(). Any Angular app — or any code that calls setAttribute('*name', …) — hits this.

Change

Add a single rule to sanitizeAttributesForXHTML:

if (name.startsWith('*')) { el.removeAttribute(name); continue }

Placed outside the stripFrameworkDirectives opt-out because it's an XML-spec rule, not a framework convention — * should always be stripped regardless of options.

__tests__/snapdom.starAttributes.test.js:

  • reproduces the EncodingError on a node with *ngIf / *ngFor / *data-custom
  • asserts the serialized SVG contains no *-prefixed attributes

Test plan

  • New tests fail on main (EncodingError + *-attrs present in SVG)
  • New tests pass with this change
  • Full suite: npx vitest run --browser.headless553 passed, 1 skipped, 0 failed
  • npm run lint clean
  • Cross-checked with related tests: snapdom.attributes.test.js, snapdom.invalidXMLChars.test.js pass unchanged

@venkateshwarreddyr venkateshwarreddyr changed the title Fix EncodingError on capture when DOM has *-prefixed HTML attributes fix(capture): drop *-prefixed attributes to keep XMLSerializer output well-formed Jul 1, 2026
@venkateshwarreddyr
venkateshwarreddyr force-pushed the fix/star-prefixed-attributes branch from ff70504 to 7a66302 Compare July 1, 2026 04:26
…put valid

HTML attribute names beginning with "*" (e.g. Angular structural
directives like *ngIf, *ngFor, or any custom *data-foo) are valid in
HTML5 but illegal in XML: "*" is not allowed as a NameStartChar.

sanitizeAttributesForXHTML already strips "@" and unknown ":"
prefixes because they survive HTML parsing but break XMLSerializer
output, leaving the resulting data: URL unparseable and triggering
"EncodingError: The source image cannot be decoded" at img.decode()
time. "*" was missing from that pass.

Add a strip rule in sanitizeAttributesForXHTML alongside the existing
"@" / namespace checks. Placed outside the stripFrameworkDirectives
opt-out because it is an XML-spec rule, not a framework convention.

Fixes zumerlab#446.

Adds a regression test covering *ngIf-style Angular directives and
arbitrary *custom-attr names.
@venkateshwarreddyr
venkateshwarreddyr force-pushed the fix/star-prefixed-attributes branch from 7a66302 to 1e706c8 Compare July 1, 2026 04:29
@tinchox5
tinchox5 merged commit 5b04c9e into zumerlab:main Jul 3, 2026
@tinchox5

tinchox5 commented Jul 3, 2026

Copy link
Copy Markdown
Member

Thank you @venkateshwarreddyr for this contribution and welcome!!

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.

EncodingError ("The source image cannot be decoded") when captured DOM contains *-prefixed attributes

2 participants