Skip to content

Commit e37c435

Browse files
committed
fix(language_server): correct position for "ignore this rule for this file" in vue/astro/svelte files (#14187)
Put the correct position for the `disable this rule for this file` code action on Vue and other files. ![ignore-fix-vue](https://github.com/user-attachments/assets/6b26da29-4a28-47a5-81c8-c90b07c47cea) closes #11707
1 parent 7a0eb57 commit e37c435

File tree

8 files changed

+94
-47
lines changed

8 files changed

+94
-47
lines changed

crates/oxc_language_server/fixtures/linter/vue/debugger.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
<div>Hello World</div>
33
</template>
44

5-
<script>
6-
debugger
7-
</script>
5+
<script>debugger;</script>
86

97
<script setup lang="ts" generic="T extends Record<string, string>">
108
let foo: T; // test ts syntax

crates/oxc_language_server/src/snapshots/fixtures_linter_astro@debugger.astro.snap

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ fixed: Multiple(
5656
code: "// oxlint-disable no-debugger\n",
5757
range: Range {
5858
start: Position {
59-
line: 0,
59+
line: 1,
6060
character: 0,
6161
},
6262
end: Position {
63-
line: 0,
63+
line: 1,
6464
character: 0,
6565
},
6666
},
@@ -120,11 +120,11 @@ fixed: Multiple(
120120
code: "// oxlint-disable no-debugger\n",
121121
range: Range {
122122
start: Position {
123-
line: 0,
123+
line: 10,
124124
character: 0,
125125
},
126126
end: Position {
127-
line: 0,
127+
line: 10,
128128
character: 0,
129129
},
130130
},
@@ -184,11 +184,11 @@ fixed: Multiple(
184184
code: "// oxlint-disable no-debugger\n",
185185
range: Range {
186186
start: Position {
187-
line: 0,
187+
line: 14,
188188
character: 0,
189189
},
190190
end: Position {
191-
line: 0,
191+
line: 14,
192192
character: 0,
193193
},
194194
},
@@ -248,11 +248,11 @@ fixed: Multiple(
248248
code: "// oxlint-disable no-debugger\n",
249249
range: Range {
250250
start: Position {
251-
line: 0,
251+
line: 18,
252252
character: 0,
253253
},
254254
end: Position {
255-
line: 0,
255+
line: 18,
256256
character: 0,
257257
},
258258
},

crates/oxc_language_server/src/snapshots/fixtures_linter_svelte@debugger.svelte.snap

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ fixed: Multiple(
4040
code: "// oxlint-disable no-unassigned-vars\n",
4141
range: Range {
4242
start: Position {
43-
line: 0,
43+
line: 1,
4444
character: 0,
4545
},
4646
end: Position {
47-
line: 0,
47+
line: 1,
4848
character: 0,
4949
},
5050
},
@@ -88,11 +88,11 @@ fixed: Multiple(
8888
code: "// oxlint-disable no-unassigned-vars\n",
8989
range: Range {
9090
start: Position {
91-
line: 0,
91+
line: 1,
9292
character: 0,
9393
},
9494
end: Position {
95-
line: 0,
95+
line: 1,
9696
character: 0,
9797
},
9898
},
@@ -152,11 +152,11 @@ fixed: Multiple(
152152
code: "// oxlint-disable no-debugger\n",
153153
range: Range {
154154
start: Position {
155-
line: 0,
155+
line: 1,
156156
character: 0,
157157
},
158158
end: Position {
159-
line: 0,
159+
line: 1,
160160
character: 0,
161161
},
162162
},

crates/oxc_language_server/src/snapshots/fixtures_linter_vue@debugger.vue.snap

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ file: fixtures/linter/vue/debugger.vue
88
code: "eslint(no-debugger)"
99
code_description.href: "https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html"
1010
message: "`debugger` statement is not allowed\nhelp: Remove the debugger statement"
11-
range: Range { start: Position { line: 5, character: 4 }, end: Position { line: 5, character: 12 } }
11+
range: Range { start: Position { line: 4, character: 8 }, end: Position { line: 4, character: 17 } }
1212
related_information[0].message: ""
1313
related_information[0].location.uri: "file://<variable>/fixtures/linter/vue/debugger.vue"
14-
related_information[0].location.range: Range { start: Position { line: 5, character: 4 }, end: Position { line: 5, character: 12 } }
14+
related_information[0].location.range: Range { start: Position { line: 4, character: 8 }, end: Position { line: 4, character: 17 } }
1515
severity: Some(Warning)
1616
source: Some("oxc")
1717
tags: None
@@ -24,12 +24,12 @@ fixed: Multiple(
2424
code: "",
2525
range: Range {
2626
start: Position {
27-
line: 5,
28-
character: 4,
27+
line: 4,
28+
character: 8,
2929
},
3030
end: Position {
31-
line: 5,
32-
character: 12,
31+
line: 4,
32+
character: 17,
3333
},
3434
},
3535
},
@@ -40,11 +40,11 @@ fixed: Multiple(
4040
code: "// oxlint-disable-next-line no-debugger\n",
4141
range: Range {
4242
start: Position {
43-
line: 5,
43+
line: 4,
4444
character: 0,
4545
},
4646
end: Position {
47-
line: 5,
47+
line: 4,
4848
character: 0,
4949
},
5050
},
@@ -53,15 +53,15 @@ fixed: Multiple(
5353
message: Some(
5454
"Disable no-debugger for this file",
5555
),
56-
code: "// oxlint-disable no-debugger\n",
56+
code: "\n// oxlint-disable no-debugger\n",
5757
range: Range {
5858
start: Position {
59-
line: 0,
60-
character: 0,
59+
line: 4,
60+
character: 8,
6161
},
6262
end: Position {
63-
line: 0,
64-
character: 0,
63+
line: 4,
64+
character: 8,
6565
},
6666
},
6767
},
@@ -72,10 +72,10 @@ fixed: Multiple(
7272
code: "eslint(no-debugger)"
7373
code_description.href: "https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html"
7474
message: "`debugger` statement is not allowed\nhelp: Remove the debugger statement"
75-
range: Range { start: Position { line: 10, character: 4 }, end: Position { line: 10, character: 13 } }
75+
range: Range { start: Position { line: 8, character: 4 }, end: Position { line: 8, character: 13 } }
7676
related_information[0].message: ""
7777
related_information[0].location.uri: "file://<variable>/fixtures/linter/vue/debugger.vue"
78-
related_information[0].location.range: Range { start: Position { line: 10, character: 4 }, end: Position { line: 10, character: 13 } }
78+
related_information[0].location.range: Range { start: Position { line: 8, character: 4 }, end: Position { line: 8, character: 13 } }
7979
severity: Some(Warning)
8080
source: Some("oxc")
8181
tags: None
@@ -88,11 +88,11 @@ fixed: Multiple(
8888
code: "",
8989
range: Range {
9090
start: Position {
91-
line: 10,
91+
line: 8,
9292
character: 4,
9393
},
9494
end: Position {
95-
line: 10,
95+
line: 8,
9696
character: 13,
9797
},
9898
},
@@ -104,11 +104,11 @@ fixed: Multiple(
104104
code: "// oxlint-disable-next-line no-debugger\n",
105105
range: Range {
106106
start: Position {
107-
line: 10,
107+
line: 8,
108108
character: 0,
109109
},
110110
end: Position {
111-
line: 10,
111+
line: 8,
112112
character: 0,
113113
},
114114
},
@@ -120,11 +120,11 @@ fixed: Multiple(
120120
code: "// oxlint-disable no-debugger\n",
121121
range: Range {
122122
start: Position {
123-
line: 0,
123+
line: 7,
124124
character: 0,
125125
},
126126
end: Position {
127-
line: 0,
127+
line: 7,
128128
character: 0,
129129
},
130130
},

crates/oxc_linter/src/context/host.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ impl<'a> ContextHost<'a> {
174174
}
175175

176176
/// The current [`ContextSubHost`]
177-
fn current_sub_host(&self) -> &ContextSubHost<'a> {
177+
pub fn current_sub_host(&self) -> &ContextSubHost<'a> {
178178
&self.sub_hosts[self.current_sub_host_index.get()]
179179
}
180180

crates/oxc_linter/src/context/mod.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,14 @@ impl<'a> LintContext<'a> {
247247
/// Use [`LintContext::diagnostic_with_fix`] to provide an automatic fix.
248248
#[inline]
249249
pub fn diagnostic(&self, diagnostic: OxcDiagnostic) {
250+
#[cfg(not(feature = "language_server"))]
250251
self.add_diagnostic(Message::new(diagnostic, PossibleFixes::None));
252+
253+
#[cfg(feature = "language_server")]
254+
self.add_diagnostic(
255+
Message::new(diagnostic, PossibleFixes::None)
256+
.with_section_offset(self.parent.current_sub_host().source_text_offset),
257+
);
251258
}
252259

253260
/// Report a lint rule violation and provide an automatic fix.
@@ -358,7 +365,14 @@ impl<'a> LintContext<'a> {
358365
{
359366
let (diagnostic, fix) = self.create_fix(fix_kind, fix, diagnostic);
360367
if let Some(fix) = fix {
368+
#[cfg(not(feature = "language_server"))]
361369
self.add_diagnostic(Message::new(diagnostic, PossibleFixes::Single(fix)));
370+
371+
#[cfg(feature = "language_server")]
372+
self.add_diagnostic(
373+
Message::new(diagnostic, PossibleFixes::Single(fix))
374+
.with_section_offset(self.parent.current_sub_host().source_text_offset),
375+
);
362376
} else {
363377
self.diagnostic(diagnostic);
364378
}
@@ -387,7 +401,14 @@ impl<'a> LintContext<'a> {
387401
if fixes_result.is_empty() {
388402
self.diagnostic(diagnostic);
389403
} else {
404+
#[cfg(not(feature = "language_server"))]
390405
self.add_diagnostic(Message::new(diagnostic, PossibleFixes::Multiple(fixes_result)));
406+
407+
#[cfg(feature = "language_server")]
408+
self.add_diagnostic(
409+
Message::new(diagnostic, PossibleFixes::Multiple(fixes_result))
410+
.with_section_offset(self.parent.current_sub_host().source_text_offset),
411+
);
391412
}
392413
}
393414

crates/oxc_linter/src/fixer/mod.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ pub struct Message<'a> {
224224
pub fixes: PossibleFixes<'a>,
225225
span: Span,
226226
fixed: bool,
227+
#[cfg(feature = "language_server")]
228+
pub section_offset: u32,
227229
}
228230

229231
impl<'new> CloneIn<'new> for Message<'_> {
@@ -235,6 +237,8 @@ impl<'new> CloneIn<'new> for Message<'_> {
235237
fixes: self.fixes.clone_in(allocator),
236238
span: self.span,
237239
fixed: self.fixed,
240+
#[cfg(feature = "language_server")]
241+
section_offset: self.section_offset,
238242
}
239243
}
240244
}
@@ -249,7 +253,20 @@ impl<'a> Message<'a> {
249253
.map(|span| Span::new(span.offset() as u32, (span.offset() + span.len()) as u32))
250254
.unwrap_or_default();
251255

252-
Self { error, span, fixes, fixed: false }
256+
Self {
257+
error,
258+
span,
259+
fixes,
260+
fixed: false,
261+
#[cfg(feature = "language_server")]
262+
section_offset: 0,
263+
}
264+
}
265+
266+
#[cfg(feature = "language_server")]
267+
pub fn with_section_offset(mut self, section_offset: u32) -> Self {
268+
self.section_offset = section_offset;
269+
self
253270
}
254271

255272
/// move the offset of all spans to the right

crates/oxc_linter/src/lsp.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,7 @@ pub fn message_to_message_with_position<'a>(
109109
) -> MessageWithPosition<'a> {
110110
let code = message.error.code.clone();
111111
let error_offset = message.span().start;
112-
// TODO: feature flag for knowing the source text section start offset of this message
113-
let section_offset = 0;
112+
let section_offset = message.section_offset;
114113

115114
let mut result = oxc_diagnostic_to_message_with_position(message.error, source_text, rope);
116115
let fixes = match &message.fixes {
@@ -224,13 +223,25 @@ fn disable_for_this_section<'a>(
224223
rope: &Rope,
225224
source_text: &str,
226225
) -> FixWithPosition<'a> {
227-
let mut start_position = offset_to_position(rope, section_offset, source_text);
228-
start_position.character = 0; // TODO: character should be set to match the first non-whitespace character in the source text to match the existing indentation.
229-
let end_position = start_position.clone();
226+
let (content, offset) = if section_offset == 0 {
227+
// JS files - keep existing behavior
228+
(Cow::Owned(format!("// oxlint-disable {rule_name}\n")), section_offset)
229+
}
230+
// Vue files or other files with section_offset > 0
231+
// Check if there's a newline at the section offset
232+
else if source_text.as_bytes().get(section_offset as usize).is_some_and(|c| *c == b'\n') {
233+
// There's a newline at section_offset, insert after it
234+
(Cow::Owned(format!("// oxlint-disable {rule_name}\n")), section_offset + 1)
235+
} else {
236+
// Not at beginning of line, add newline before comment
237+
(Cow::Owned(format!("\n// oxlint-disable {rule_name}\n")), section_offset)
238+
};
239+
240+
let position = offset_to_position(rope, offset, source_text);
230241

231242
FixWithPosition {
232-
content: Cow::Owned(format!("// oxlint-disable {rule_name}\n")),
233-
span: SpanPositionMessage::new(start_position, end_position)
243+
content,
244+
span: SpanPositionMessage::new(position.clone(), position)
234245
.with_message(Some(Cow::Owned(format!("Disable {rule_name} for this file")))),
235246
}
236247
}

0 commit comments

Comments
 (0)