Skip to content

fix: do not reuse the opening * when closing a comment#100

Open
spokodev wants to merge 1 commit into
postcss:mainfrom
spokodev:fix/comment-closing-overlap
Open

fix: do not reuse the opening * when closing a comment#100
spokodev wants to merge 1 commit into
postcss:mainfrom
spokodev:fix/comment-closing-overlap

Conversation

@spokodev

Copy link
Copy Markdown

Problem

/*/ does not round-trip — it comes back as /**/:

const valueParser = require("postcss-value-parser");
valueParser("/*/").toString();              // "/**/"
valueParser("a /*/ b").toString();          // "a /**/ b"
valueParser("/*/ hack /**/").toString();    // "/*/ hack /**/"  → "/**/ hack /**/"

/*/ is an unclosed comment whose content is /, but it is parsed as a closed, empty comment ({ type: "comment", value: "" }), and stringifying that yields /**/. This breaks the lossless round-trip the parser is designed for, and /*/ shows up in real stylesheets as a comment-toggle hack.

Root cause

In lib/parse.js the closing delimiter is located with:

next = value.indexOf("*/", pos);

pos points at the opening /, so the search range includes the opening /*. For /*/, indexOf("*/", 0) finds a */ at index 1 — i.e. it reuses the * of the opening /* as the * of the closing */. The comment is then treated as closed with empty content.

Fix

Start the search past the opening delimiter so the two *s can't overlap:

next = value.indexOf("*/", pos + 2);

Now /*/ has no */ after the opening, so it is correctly an unclosed comment with content /. Already-closed comments are unaffected: /**/, /*c*/, /****/ still find their real closing */.

Test plan

  • New parse test: /*/ parses to { type: "comment", value: "/", unclosed: true } (fails on main).
  • Round-trip cases added to the i/o test (/*/, a /*/ b, /*/ comment hack /**/).
  • A property check over 300k generated CSS values found this as the only round-trip divergence; it drops to zero with the fix. Full suite green (node --test), oxlint/oxfmt clean.

`indexOf("*/", pos)` started searching at the opening `/`, so the `*` of
the opening `/*` could be matched as the `*` of a closing `*/`. As a
result `/*/` was parsed as a closed, empty comment instead of an unclosed
comment whose content is `/`, and stringifying it produced `/**/` —
breaking the lossless round-trip (`/*/` is also a known CSS comment hack).

Start the search past the opening delimiter (`pos + 2`).
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.

1 participant