Skip to content

fix: #282 harden src/jsx-loader.js — 8 JSX + inferred-observability defects#283

Open
jstockdi wants to merge 8 commits into
ProjectEvergreen:masterfrom
Battle-Creek-LLC:fix/issue-282-jsx-loader-hardening
Open

fix: #282 harden src/jsx-loader.js — 8 JSX + inferred-observability defects#283
jstockdi wants to merge 8 commits into
ProjectEvergreen:masterfrom
Battle-Creek-LLC:fix/issue-282-jsx-loader-hardening

Conversation

@jstockdi

Copy link
Copy Markdown

Related Issue

Resolves #282

Summary of Changes

Eight correctness/DX defects in src/jsx-loader.js, one commit (fix + regression test) each. Every regression test fails on the unpatched compiler and passes with its fix; all 8 new jsx-* cases pass together (npm run test:jsx green, coverage above .c8rc.json gates), and npm test is unaffected.

  1. Warn on unsupported JSX expressions instead of silently dropping them. Unsupported child expressions (calls, ternaries, binary ops, template literals, .map() lists, computed members) produced no output and no diagnostic; a console.warn now fires from the fall-through naming the expression. Also handles the child Literal idiom ({' '}, {'text'}, {42}) that was itself being dropped. Non-fatal — behavior is otherwise unchanged.
  2. Render {this.count.get()} signal reads directly instead of compiling to ${undefined.get()} (which crashed SSR). Mirrors the destructured {count.get()} form; the destructured path is unchanged. (The chained {this.todos.get().length} variant is left as a follow-up.)
  3. export const inferredObservability = false now disables inferred observability — used the parsed literal value instead of Boolean(init.raw) (which was true for the source text "false").
  4. Resolve the component name for the export default Identifier form (class X extends HTMLElement {}; customElements.define(...); export default X;), so the effect-append pass no longer emits undefined.$$tmpl0(...). The inline export default class Name form is unaffected.
  5. Don't inject duplicate observedAttributes / attributeChangedCallback when the component defines its own — the dead hasOwnObservedAttributes flag is now actually set during the class walk, honoring the existing skip guards.
  6. Escape inline arrow-handler strings and rewrite this via the AST. A double-quoted string inside an onclick={() => …} handler no longer breaks the attribute, and this inside string literals is left intact (ThisExpression nodes are rewritten via acorn-walk instead of a /this./g regex).
  7. Guard node.superClass for a class without extends — a plain helper class Foo {} in a .jsx file no longer crashes compilation with Cannot read properties of null (reading 'name').
  8. Serialize only the body fragment for a document-rooted JSX render — a <body>-rooted "page" component no longer emits a nested full <html><head></head><body>…</body></html> document. Normal fragment rendering is byte-identical (guarded on the full-document parse path).

No breaking changes. Each fix is minimal and confined to its concern; defect 1 is diagnostic-only (a warning, not a hard error), so builds that currently produce partial output keep building, now with a hint about what was dropped.

@jstockdi jstockdi self-assigned this Jul 18, 2026
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.

src/jsx-loader.js: several correctness/DX defects in JSX + inferred-observability compilation

1 participant