Repository: swc-project/swc (rust)

Issue:
Certain types of comments (like: `//!`) are not removed during minification
### Describe the bug

NOTE: This was originally posted as a Next.js bug: https://github.com/vercel/next.js/issues/52600 , but it turns out that it can be isolated to SWC completely (reproduction url below).

Special comments like ones starting with: `//!` (that are still valid comments, like the ones from Better Comments) are not removed during minification.
![253031366-e560e512-34b2-4cc2-874b-1c0a24411ddb](https://github.com/swc-project/swc/assets/2103443/119ebd0b-6ad3-453b-a75d-3d5313bc4a25)


### Input code

_No response_

### Config

_No response_

### Playground link

https://play.swc.rs/?version=1.3.66&code=H4sIAAAAAAAAA2VSTWsbMRC9%2B1e8npyakL2HtlDagwsNgdjQY1BXsysR7YwZae0Y4%2F%2Fe0XrbJI1uGt68L6lZrfDVexxlVCgl2jsuaMUTAimhE0UJhJjzSChimJ2KH1vCqlnQ8060wFPnxlTQjdyWKIy1DHT1EacFDF9GZXzycW%2B3y2ma7f33%2B1t8C9Q%2BIXamELNJIJeYEpjIk4frCl3E3c409y5BuunOdDDTuHPsetJXtB%2BwDdVzSnKI3MPWdqTliCH2oSATDUjxyeKUKuelglhMnvubNzxrOdCe9HpGxqEGrdVEhqivxsToDWOzB3KtpVcZ4GNunXrje0M3ubZSl9m65WJLGcJWYjh6dVNnwVIS1%2FGEblM01M27cC%2Frc22Vds7XBsc94TeVA9GFZkNqMbCJBnogNuP%2FW3PsJ%2BQ%2FJ9fwl6euU6U%2B5jJt%2FW0%2FJzH5EtzcIVdF%2ByevKF5s%2B%2BpIZczpuKHyg5l0vb37%2Bfl0wuNjKEO6xXJN9l74JZr8EufzvNt8WZwXfwBOxzIxnwIAAA%3D%3D&config=H4sIAAAAAAAAA1WNvQ7CMAwG9z5F5JmVhZWFBd7BKi4KOD%2ByXalV1XcnLQmCzd%2BddF465%2BCpPZzcUs4yMoqSfHchOkfDqRCwOZP24rPBoVnTTZmMtJP1I8AEow5JQpFxZG4Y5UG2tUiPNQKcklKNVESTkUTkC3Em0SIHZG32RZTPjKo3DPQn9%2FcQfPTD%2FFMEr9d0H7l96dbuDVk6N%2Fn6AAAA

### Expected behavior

All comments are removed from the code.

### Actual behavior

Only some comments are removed from the code. Others are included, along with newlines into the minified result.

### Version

1.3.66

### Additional context

_No response_

Pull request:
fix(es/minifier): Drop line comments starting with `!`
**Description:**


**Related issue:**

 - Closes #7653

Patch:
diff --git a/crates/swc/src/lib.rs b/crates/swc/src/lib.rs
index 64edb43cf0..8514e23853 100644
--- a/crates/swc/src/lib.rs
+++ b/crates/swc/src/lib.rs
@@ -120,7 +120,11 @@ use std::{
 
 use anyhow::{bail, Context, Error};
 use atoms::JsWord;
-use common::{collections::AHashMap, comments::SingleThreadedComments, errors::HANDLER};
+use common::{
+    collections::AHashMap,
+    comments::{CommentKind, SingleThreadedComments},
+    errors::HANDLER,
+};
 use config::{IsModule, JsMinifyCommentOption, JsMinifyOptions, OutputCharset};
 use jsonc_parser::{parse_to_serde_value, ParseOptions};
 use once_cell::sync::Lazy;
@@ -696,7 +700,15 @@ pub(crate) fn minify_file_comments(
         BoolOr::Data(JsMinifyCommentOption::PreserveSomeComments) => {
             let preserve_excl = |_: &BytePos, vc: &mut Vec<Comment>| -> bool {
                 // Preserve license comments.
-                vc.retain(|c: &Comment| c.text.contains("@license") || c.text.starts_with('!'));
+                //
+                // See https://github.com/terser/terser/blob/798135e04baddd94fea403cfaab4ba8b22b1b524/lib/output.js#L175-L181
+                vc.retain(|c: &Comment| {
+                    c.text.contains("@lic")
+                        || c.text.contains("@preserve")
+                        || c.text.contains("@copyright")
+                        || c.text.contains("@cc_on")
+                        || (c.kind == CommentKind::Block && c.text.starts_with('!'))
+                });
                 !vc.is_empty()
             };
             let (mut l, mut t) = comments.borrow_all_mut();


Test patch:
diff --git a/crates/swc/tests/fixture/issues-7xxx/7653/input/.swcrc b/crates/swc/tests/fixture/issues-7xxx/7653/input/.swcrc
new file mode 100644
index 0000000000..98f2c5ee96
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7653/input/.swcrc
@@ -0,0 +1,15 @@
+{
+    "jsc": {
+        "parser": {
+            "syntax": "typescript",
+            "tsx": true
+        },
+        "transform": null,
+        "target": "es5",
+        "loose": true,
+        "externalHelpers": false,
+        "keepClassNames": false,
+    },
+    "minify": true,
+    "isModule": true
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-7xxx/7653/input/1.js b/crates/swc/tests/fixture/issues-7xxx/7653/input/1.js
new file mode 100644
index 0000000000..4216ab929b
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7653/input/1.js
@@ -0,0 +1,12 @@
+/** Add your relevant code here for the issue to reproduce */
+export default function Home() {
+    return <div
+        //TODO: Check if this is still needed after the approval of the new Ad Manager
+        //! The following property might seem like it is doing nothing.
+        //! However, it is important in order to prevent React from discarding
+        //! the node's contents once hydration happens on the client.
+        //! The contents of this node might change between the Server Side Rendering
+        //! and the hydration, due to the registering of the slots that is done before hydration.
+        dangerouslySetInnerHTML={{ __html: 'Hello World' }}
+    />
+}
diff --git a/crates/swc/tests/fixture/issues-7xxx/7653/output/1.js b/crates/swc/tests/fixture/issues-7xxx/7653/output/1.js
new file mode 100644
index 0000000000..0e2994b7a9
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-7xxx/7653/output/1.js
@@ -0,0 +1,1 @@
+export default function Home(){return React.createElement("div",{dangerouslySetInnerHTML:{__html:"Hello World"}})}