Repository: unocss/unocss (TypeScript)

Issue:
Curly braces in comments lead to wrong output
### UnoCSS version

v66.1.0

### Describe the bug

```css
.aaa {
  @apply text-blue-500;
  font-size: 1.5em;
  /* {} ← empty curly brace in comment will lead to wrong parsing */
  font-weight: 900;
}
```

generates

```css
/* layer: playground */
.aaa {← empty curly brace in comment will lead to wrong parsing */
font-weight: 900;
}
```

https://github.com/user-attachments/assets/c0b30efd-b96f-4c72-8bb5-d3ad4aad91cc

### Reproduction

[https://unocss.dev/play/~](https://unocss.dev/play/#html=DwEwlgbgBAxgNgQwM5ILwCIFfQPgC4AWYSUSBA9gK5whQBGAplIgE4DmTCAdrXXJQ2AB6cBBwAoYAAccdSnijkuMJoQYtOGqEIDeAHSQBqPQF8hUMFygBhAMq3xMcgFtnDLniQAaKGtjkQJkYAM3ItPydXdwUELWdiJEs2ADpJIRkgA&config=JYWwDg9gTgLgBAbwFBzgEwKYDNgDsMDCEuOA5gDQpxhQYDOGMAsnsJQL5xZQQhwDkAV1wQAxnTr8koSLDgwoAQ1x0s0EBigARYLVExgAN3pceffgAFhYiQHoFy1es0BaNLoz6j9KUgwAPWXhMLEVBABtg7DxCYjIACmRUGnpGOgAuOABtFIZmVniASgBdSlQHFTUoDSgM7Iqnas0dPQNjOiLipHZCpCA&css=HQQzAIG8Ch3ABEAHJAbAnuALgUwB5YC0ARqgK46ECsADDQNyzgBmA9gHZEDOAlgF44AXOACMwKjgC2jOAHoAVFAC%2B4ebKZtOhAO44eAcwAWWYQE46jJdCA&options=N4IgLgTghgdgzgMwPYQLYGECucxIwZXxAC4EoAbOAUwBpxp5k0AJMVcksyqgXyA&version=66.1.0)

### System Info

_No response_

### Validations

- [x] Read the [Contributing Guidelines](https://github.com/unocss/unocss/blob/main/.github/CONTRIBUTING.md).
- [x] Check that there isn't [already an issue](https://github.com/unocss/unocss/issues) that reports the same bug to avoid creating a duplicate.
- [x] Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/unocss/unocss/discussions) or join our [Discord Chat Server](https://chat.antfu.me).
- [x] The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.


Discussion:

Patch:
diff --git a/packages-presets/transformer-directives/src/transform.ts b/packages-presets/transformer-directives/src/transform.ts
index 271fd1d4e3..9f39020e29 100644
--- a/packages-presets/transformer-directives/src/transform.ts
+++ b/packages-presets/transformer-directives/src/transform.ts
@@ -71,10 +71,16 @@ export async function transformDirectives(
 
   await Promise.all(stack)
 
-  // Remove empty blocks
   const oldCode = code.toString()
+  // transformDirectives has recursive behavior, only for the last call
   if (!isHasApply(oldCode)) {
-    const newCode = oldCode.replace(/[^{}]*\{\s*\}\s*/g, '')
+    const newCode = oldCode.replace(/([^{}]+)\{\s*\}\s*/g, (m, selector) => {
+      // Only remove empty rules with valid selectors
+      if (/^[\s\w\-.,#:[\]=*"'>~+^$|()\\]+$/.test(selector.trim()))
+        return ''
+      return m
+    })
+
     if (newCode !== oldCode)
       code.update(0, code.original.length, newCode)
   }


Test patch:
diff --git a/test/transformer-directives.test.ts b/test/transformer-directives.test.ts
index 92d13c8108..c8628c1de2 100644
--- a/test/transformer-directives.test.ts
+++ b/test/transformer-directives.test.ts
@@ -655,6 +655,28 @@ div {
       `)
   })
 
+  it('@apply with empty block comments', async () => {
+    const result = await transform(
+      `
+.aaa {
+  @apply text-blue-500;
+  /* {} empty curly brace in comment will lead to wrong parsing */
+  font-weight: 900;
+}
+      `,
+    )
+    expect(result)
+      .toMatchInlineSnapshot(`
+        ".aaa {
+          --un-text-opacity: 1;
+          color: rgb(59 130 246 / var(--un-text-opacity));
+          /* {} empty curly brace in comment will lead to wrong parsing */
+          font-weight: 900;
+        }
+        "
+      `)
+  })
+
   it('@apply selector group', async () => {
     const result = await transform(
       '.btn { @apply: sgroup:bg-orange }',