#368·defuddle

addons-linter flags the three innerHTML sites in utils/dom.ts (AMO review noise for bundling extensions) — linter-clean equivalents?

Author: colangeloCreated Aug 20, 2026Updated Aug 20, 2026

Context

Defuddle is bundled into a Firefox WebExtension (a web clipper) submitted to addons.mozilla.org. AMO's validator (addons-linter, the same engine web-ext lint runs) flags three UNSAFE_VAR_ASSIGNMENT warnings, all inside Defuddle — the only innerHTML assignments in the whole bundle:

  • src/utils/dom.ts:31decodeHTMLEntities: textarea.innerHTML = text
  • src/utils/dom.ts:105parseHTML: template.innerHTML = html
  • src/utils/dom.ts:111parseHTML fallback: div.innerHTML = html

They are warnings, not errors ("Add-on passed validation"), and the idioms are safe — a detached <textarea> never executes anything, and <template> content is inert. But every extension that bundles Defuddle will carry these three warnings into AMO review, and addons-linter offers no inline suppression, so the only place to explain them is the reviewer notes of each add-on.

Ask

Would you take a PR that keeps the exact same parsing semantics but avoids the innerHTML setter the linter matches on? Two candidates, both relying on DOMParser (available wherever document is, and in the linkedom path too?):

  1. decodeHTMLEntities:

    typescript
    const doc2 = new DOMParser().parseFromString(`<textarea>${text}</textarea>`, 'text/html');
    return (doc2.querySelector('textarea') as HTMLTextAreaElement).value;

    <textarea> is RCDATA in a full parse exactly as it is for the fragment case, so entity decoding matches — the one divergence is a literal </textarea> in the input.

  2. parseHTML:

    typescript
    const doc2 = new DOMParser().parseFromString(`<template>${html}</template>`, 'text/html');
    return doc2.querySelector('template')!.content;  // already inert

    A <template> in a full parse enters the same "in template" insertion mode the fragment algorithm uses for a template context, so the resulting tree is the same; again the edge is a literal </template> inside html.

If the edge cases make that unattractive, an alternative is to leave the code as-is and add a short note in the README for extension authors ("these three warnings are expected; here is what they are"), which downstream projects could link from their AMO reviewer notes.

Happy to open the PR with tests for both functions (including the edge cases above) if either direction works for you. Thanks for Defuddle — it's doing the heavy lifting of an Evernote-grade clipper very well.