From d0daa44328814aa5d6d0fb677d51769cd87e3ba4 Mon Sep 17 00:00:00 2001 From: miga-heygen Date: Tue, 1 Sep 2026 20:17:46 +0000 Subject: [PATCH 1/2] fix(core): catch PostCSS parse errors instead of dropping compositions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invalid CSS in a sub-composition style block made postcss.parse throw inside scopeCssToComposition. The throw propagated to the composition loader's catch block, which emptied the host — silently dropping the entire scene. Lint swallowed the same error via catch { continue }, reporting 0 warnings. Two fixes: - Runtime: wrap postcss.parse in try/catch and return the original (unscoped) CSS on failure, so the composition still mounts - Lint: emit a css_parse_error finding instead of silently continuing Fixes #3585. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../core/src/compiler/compositionScoping.test.ts | 6 ++++++ packages/core/src/compiler/compositionScoping.ts | 7 ++++++- packages/lint/src/rules/core.test.ts | 16 ++++++++++++++++ packages/lint/src/rules/core.ts | 7 ++++++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/core/src/compiler/compositionScoping.test.ts b/packages/core/src/compiler/compositionScoping.test.ts index 7ba39a5fbc..98e3f61046 100644 --- a/packages/core/src/compiler/compositionScoping.test.ts +++ b/packages/core/src/compiler/compositionScoping.test.ts @@ -1054,4 +1054,10 @@ describe("wrapInlineScriptWithErrorBoundary — + + `; + const result = await lintHyperframeHtml(html); + const finding = result.findings.find((f) => f.code === "css_parse_error"); + expect(finding).toBeDefined(); + expect(finding?.severity).toBe("error"); + expect(finding?.message).toContain("Missed semicolon"); + }); + }); }); diff --git a/packages/lint/src/rules/core.ts b/packages/lint/src/rules/core.ts index 3461a59422..8d784da2ff 100644 --- a/packages/lint/src/rules/core.ts +++ b/packages/lint/src/rules/core.ts @@ -312,7 +312,12 @@ export const coreRules: Array<(ctx: LintContext) => HyperframeLintFinding[]> = [ let root: postcss.Root; try { root = postcss.parse(style.content); - } catch { + } catch (error) { + findings.push({ + code: "css_parse_error", + severity: "error", + message: `CSS parse error: ${error instanceof Error ? error.message : "unknown"}`, + }); continue; } root.walkRules((rule) => { From 989110c6cc4a99668e152ff21f2af370d27a12db Mon Sep 17 00:00:00 2001 From: miga-heygen Date: Thu, 3 Sep 2026 04:02:03 +0000 Subject: [PATCH 2/2] fix: drop unparseable CSS instead of leaking it unscoped Return "" on PostCSS parse failure so sub-composition stylesheets that cannot be scoped are dropped rather than injected unscoped into the parent document. Updates test fixture to use valid+malformed CSS that demonstrates the leak risk. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/core/src/compiler/compositionScoping.test.ts | 9 ++++++--- packages/core/src/compiler/compositionScoping.ts | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/core/src/compiler/compositionScoping.test.ts b/packages/core/src/compiler/compositionScoping.test.ts index 98e3f61046..80a63c059f 100644 --- a/packages/core/src/compiler/compositionScoping.test.ts +++ b/packages/core/src/compiler/compositionScoping.test.ts @@ -1055,9 +1055,12 @@ describe("wrapInlineScriptWithErrorBoundary —