diff --git a/src/css/rules/style.zig b/src/css/rules/style.zig index 69b1a7087b..3893251310 100644 --- a/src/css/rules/style.zig +++ b/src/css/rules/style.zig @@ -216,6 +216,7 @@ pub fn StyleRule(comptime R: type) type { var handler_context = context.handler_context.child(.style_rule); std.mem.swap(css.PropertyHandlerContext, &context.handler_context, &handler_context); try this.rules.minify(context, unused); + std.mem.swap(css.PropertyHandlerContext, &context.handler_context, &handler_context); if (unused and this.rules.v.items.len == 0) { return true; } diff --git a/test/regression/issue/25794.test.ts b/test/regression/issue/25794.test.ts new file mode 100644 index 0000000000..4cd2e0edf4 --- /dev/null +++ b/test/regression/issue/25794.test.ts @@ -0,0 +1,86 @@ +import { expect, test } from "bun:test"; +import { bunEnv, bunExe, tempDirWithFiles } from "harness"; + +test("CSS logical properties should not be stripped when nested rules are present", async () => { + // Test for regression of issue #25794: CSS logical properties (e.g., inset-inline-end) + // are stripped from bundler output when they appear in a nested selector that also + // contains further nested rules (like pseudo-elements). + + const dir = tempDirWithFiles("css-logical-properties-nested", { + "input.css": `.test-longform { + background-color: teal; + + &.test-longform--end { + inset-inline-end: 20px; + + &:after { + content: ""; + } + } +} +`, + }); + + await using proc = Bun.spawn({ + cmd: [bunExe(), "build", "input.css", "--outdir", "out"], + env: bunEnv, + cwd: dir, + stdout: "pipe", + stderr: "pipe", + }); + + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + + // Verify the output CSS contains the logical property fallbacks + const outputContent = await Bun.file(`${dir}/out/input.css`).text(); + + // Helper function to normalize CSS output for snapshots + function normalizeCSSOutput(output: string): string { + return output + .replace(/\/\*.*?\*\//g, "/* [path] */") // Replace comment paths + .trim(); + } + + // The output should contain LTR/RTL fallback rules for inset-inline-end + // inset-inline-end: 20px should generate: + // - right: 20px for LTR languages + // - left: 20px for RTL languages + // The bundler generates vendor-prefixed variants for browser compatibility + expect(normalizeCSSOutput(outputContent)).toMatchInlineSnapshot(` + "/* [path] */ + .test-longform { + background-color: teal; + } + + .test-longform.test-longform--end:not(:-webkit-any(:lang(ae), :lang(ar), :lang(arc), :lang(bcc), :lang(bqi), :lang(ckb), :lang(dv), :lang(fa), :lang(glk), :lang(he), :lang(ku), :lang(mzn), :lang(nqo), :lang(pnb), :lang(ps), :lang(sd), :lang(ug), :lang(ur), :lang(yi))) { + right: 20px; + } + + .test-longform.test-longform--end:not(:-moz-any(:lang(ae), :lang(ar), :lang(arc), :lang(bcc), :lang(bqi), :lang(ckb), :lang(dv), :lang(fa), :lang(glk), :lang(he), :lang(ku), :lang(mzn), :lang(nqo), :lang(pnb), :lang(ps), :lang(sd), :lang(ug), :lang(ur), :lang(yi))) { + right: 20px; + } + + .test-longform.test-longform--end:not(:is(:lang(ae), :lang(ar), :lang(arc), :lang(bcc), :lang(bqi), :lang(ckb), :lang(dv), :lang(fa), :lang(glk), :lang(he), :lang(ku), :lang(mzn), :lang(nqo), :lang(pnb), :lang(ps), :lang(sd), :lang(ug), :lang(ur), :lang(yi))) { + right: 20px; + } + + .test-longform.test-longform--end:-webkit-any(:lang(ae), :lang(ar), :lang(arc), :lang(bcc), :lang(bqi), :lang(ckb), :lang(dv), :lang(fa), :lang(glk), :lang(he), :lang(ku), :lang(mzn), :lang(nqo), :lang(pnb), :lang(ps), :lang(sd), :lang(ug), :lang(ur), :lang(yi)) { + left: 20px; + } + + .test-longform.test-longform--end:-moz-any(:lang(ae), :lang(ar), :lang(arc), :lang(bcc), :lang(bqi), :lang(ckb), :lang(dv), :lang(fa), :lang(glk), :lang(he), :lang(ku), :lang(mzn), :lang(nqo), :lang(pnb), :lang(ps), :lang(sd), :lang(ug), :lang(ur), :lang(yi)) { + left: 20px; + } + + .test-longform.test-longform--end:is(:lang(ae), :lang(ar), :lang(arc), :lang(bcc), :lang(bqi), :lang(ckb), :lang(dv), :lang(fa), :lang(glk), :lang(he), :lang(ku), :lang(mzn), :lang(nqo), :lang(pnb), :lang(ps), :lang(sd), :lang(ug), :lang(ur), :lang(yi)) { + left: 20px; + } + + .test-longform.test-longform--end:after { + content: ""; + }" + `); + + // Should exit successfully + expect(exitCode).toBe(0); +});