diff --git a/crates/oxc_linter/src/rules/unicorn/prefer_string_raw.rs b/crates/oxc_linter/src/rules/unicorn/prefer_string_raw.rs index 952dd6ab8c..4e434257e2 100644 --- a/crates/oxc_linter/src/rules/unicorn/prefer_string_raw.rs +++ b/crates/oxc_linter/src/rules/unicorn/prefer_string_raw.rs @@ -98,11 +98,10 @@ impl Rule for PreferStringRaw { return; } AstKind::ObjectProperty(prop) => { - let PropertyKey::StringLiteral(key) = &prop.key else { - return; - }; - - if !prop.computed && string_literal.span == key.span { + if let PropertyKey::StringLiteral(key) = &prop.key + && !prop.computed + && string_literal.span == key.span + { return; } } @@ -264,6 +263,7 @@ fn test() { r#"interface EventSchemas { "foo\\bar": Record; }"#, r#"interface Methods { "foo\\bar"(): void; }"#, r#"let x: "a\\b";"#, + r"const o = { newline: 'a\\b\nc', trail: 'a\\', interpolation: 'a\\b${foo}', tick: 'a\\b`' };", ]; let fail = vec![ @@ -280,6 +280,12 @@ fn test() { r"for (const f of'a\\b') {}", // Non-ASCII characters without trailing backslash - should be fixed r"const a = 'c:\\someöäü\\path';", + r#"export const o = { b: "a\\b" };"#, + r#"export const s = "a\\b";"#, + r#"export const p = { "k": "a\\b" };"#, + r#"const o = { 0: "a\\b", [key]: "a\\b", [0]: "a\\b", 1n: "a\\b", ["k"]: "a\\b" };"#, + r#"const o = { "a\\b": "c\\d", ["a\\b"]: "c\\d" };"#, + r"const o = { blank: ' \\t' };", ]; let fix = vec![ @@ -302,6 +308,18 @@ fn test() { (r"const a = () => void'a\\b';", r"const a = () => void String.raw`a\b`;"), // Non-ASCII characters (r"const a = 'c:\\someöäü\\path';", r"const a = String.raw`c:\someöäü\path`;"), + (r#"export const o = { b: "a\\b" };"#, r"export const o = { b: String.raw`a\b` };"), + (r#"export const s = "a\\b";"#, r"export const s = String.raw`a\b`;"), + (r#"export const p = { "k": "a\\b" };"#, r#"export const p = { "k": String.raw`a\b` };"#), + ( + r#"const o = { 0: "a\\b", [key]: "a\\b", [0]: "a\\b", 1n: "a\\b", ["k"]: "a\\b" };"#, + r#"const o = { 0: String.raw`a\b`, [key]: String.raw`a\b`, [0]: String.raw`a\b`, 1n: String.raw`a\b`, ["k"]: String.raw`a\b` };"#, + ), + ( + r#"const o = { "a\\b": "c\\d", ["a\\b"]: "c\\d" };"#, + r#"const o = { "a\\b": String.raw`c\d`, [String.raw`a\b`]: String.raw`c\d` };"#, + ), + (r"const o = { blank: ' \\t' };", r"const o = { blank: String.raw` \t` };"), ]; Tester::new(PreferStringRaw::NAME, PreferStringRaw::PLUGIN, pass, fail) diff --git a/crates/oxc_linter/src/snapshots/unicorn_prefer_string_raw.snap b/crates/oxc_linter/src/snapshots/unicorn_prefer_string_raw.snap index 2ff626a8c2..fd8423fa9e 100644 --- a/crates/oxc_linter/src/snapshots/unicorn_prefer_string_raw.snap +++ b/crates/oxc_linter/src/snapshots/unicorn_prefer_string_raw.snap @@ -85,3 +85,87 @@ source: crates/oxc_linter/src/tester.rs · ─────────────────── ╰──── help: Replace `'c:\\someöäü\\path'` with `String.raw`c:\someöäü\path``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:23] + 1 │ export const o = { b: "a\\b" }; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:18] + 1 │ export const s = "a\\b"; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:25] + 1 │ export const p = { "k": "a\\b" }; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:16] + 1 │ const o = { 0: "a\\b", [key]: "a\\b", [0]: "a\\b", 1n: "a\\b", ["k"]: "a\\b" }; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:31] + 1 │ const o = { 0: "a\\b", [key]: "a\\b", [0]: "a\\b", 1n: "a\\b", ["k"]: "a\\b" }; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:44] + 1 │ const o = { 0: "a\\b", [key]: "a\\b", [0]: "a\\b", 1n: "a\\b", ["k"]: "a\\b" }; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:56] + 1 │ const o = { 0: "a\\b", [key]: "a\\b", [0]: "a\\b", 1n: "a\\b", ["k"]: "a\\b" }; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:71] + 1 │ const o = { 0: "a\\b", [key]: "a\\b", [0]: "a\\b", 1n: "a\\b", ["k"]: "a\\b" }; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:21] + 1 │ const o = { "a\\b": "c\\d", ["a\\b"]: "c\\d" }; + · ────── + ╰──── + help: Replace `"c\\d"` with `String.raw`c\d``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:30] + 1 │ const o = { "a\\b": "c\\d", ["a\\b"]: "c\\d" }; + · ────── + ╰──── + help: Replace `"a\\b"` with `String.raw`a\b``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:39] + 1 │ const o = { "a\\b": "c\\d", ["a\\b"]: "c\\d" }; + · ────── + ╰──── + help: Replace `"c\\d"` with `String.raw`c\d``. + + ⚠ unicorn(prefer-string-raw): `String.raw` should be used to avoid escaping `\`. + ╭─[prefer_string_raw.tsx:1:20] + 1 │ const o = { blank: ' \\t' }; + · ────── + ╰──── + help: Replace `' \\t'` with `String.raw` \t``.