Skip to content

Commit bc1408c

Browse files
committed
refactor(linter): remove fixer eslint compat option (#22076)
Remove the now-redundant fixer eslint_compat option now that ESLint-compatible adjacent-fix handling is the only behavior. follow on from #22071
1 parent fa88857 commit bc1408c

5 files changed

Lines changed: 14 additions & 75 deletions

File tree

apps/oxlint/src-js/bindings.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export declare const enum Severity {
4141
*
4242
* Fix ranges are converted from UTF-16 code units to UTF-8 bytes.
4343
*/
44-
export declare function applyFixes(sourceText: string, fixesJson: string, eslintCompat: boolean): string | null
44+
export declare function applyFixes(sourceText: string, fixesJson: string): string | null
4545

4646
/**
4747
* Get offset within a `Uint8Array` which is aligned on `BLOCK_ALIGN`.

apps/oxlint/src-js/package/rule_tester.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ interface Config {
118118
*
119119
* If `true`:
120120
* - Column offsets in diagnostics are incremented by 1.
121-
* - Fixes which are adjacent to each other are considered overlapping, and only the first fix is applied.
122121
* - Defaults `sourceType` to "module" if not provided (otherwise default is "unambiguous").
123122
* - Disallows `sourceType: "unambiguous"`.
124123
* - Allows `null` as property value for `globals`.
@@ -674,9 +673,7 @@ function assertInvalidTestCasePasses(test: InvalidTestCase, plugin: Plugin, conf
674673

675674
// Test output after fixes
676675
const { code } = test;
677-
const eslintCompat = test.eslintCompat === true;
678-
679-
let fixedCode = runFixes(diagnostics, code, eslintCompat);
676+
let fixedCode = runFixes(diagnostics, code);
680677
if (fixedCode === null) fixedCode = code;
681678

682679
// Re-lint and re-fix for additional passes if `recursive` option used
@@ -687,7 +684,7 @@ function assertInvalidTestCasePasses(test: InvalidTestCase, plugin: Plugin, conf
687684
if (extraPassCount > 0 && fixedCode !== code) {
688685
for (let pass = 0; pass < extraPassCount; pass++) {
689686
const diagnostics = lint({ ...test, code: fixedCode }, plugin);
690-
const newFixedCode = runFixes(diagnostics, fixedCode, eslintCompat);
687+
const newFixedCode = runFixes(diagnostics, fixedCode);
691688
if (newFixedCode === null) break;
692689
fixedCode = newFixedCode;
693690
}
@@ -719,14 +716,14 @@ function assertInvalidTestCasePasses(test: InvalidTestCase, plugin: Plugin, conf
719716
* @returns Fixed code, or `null` if no fixes to apply
720717
* @throws {Error} If error when applying fixes
721718
*/
722-
function runFixes(diagnostics: Diagnostic[], code: string, eslintCompat: boolean): string | null {
719+
function runFixes(diagnostics: Diagnostic[], code: string): string | null {
723720
const fixGroups: FixReport[][] = [];
724721
for (const diagnostic of diagnostics) {
725722
if (diagnostic.fixes !== null) fixGroups.push(diagnostic.fixes);
726723
}
727724
if (fixGroups.length === 0) return null;
728725

729-
const fixedCode = applyFixes(code, JSON.stringify(fixGroups), eslintCompat);
726+
const fixedCode = applyFixes(code, JSON.stringify(fixGroups));
730727
if (fixedCode === null) throw new Error("Failed to apply fixes");
731728

732729
return fixedCode;
@@ -936,8 +933,6 @@ function assertSuggestionsAreCorrect(
936933
`Instead found ${actualSuggestions.length} suggestion${actualSuggestions.length > 1 ? "s" : ""}.`,
937934
);
938935

939-
const eslintCompat = test.eslintCompat === true;
940-
941936
for (let i = 0; i < expectedSuggestions.length; i++) {
942937
const actual = actualSuggestions[i]!;
943938
const expected = expectedSuggestions[i]!;
@@ -949,7 +944,7 @@ function assertSuggestionsAreCorrect(
949944
// Validate output
950945
assert(Object.hasOwn(expected, "output"), `${prefix}: \`output\` property is required`);
951946

952-
const suggestedCode = applyFixes(test.code, JSON.stringify([actual.fixes]), eslintCompat);
947+
const suggestedCode = applyFixes(test.code, JSON.stringify([actual.fixes]));
953948
assert(suggestedCode !== null, `${prefix}: Failed to apply suggestion fix`);
954949

955950
assert.strictEqual(

apps/oxlint/src/js_plugins/fix.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const BOM_LEN: u32 = BOM.len() as u32;
2323
/// Fix ranges are converted from UTF-16 code units to UTF-8 bytes.
2424
#[napi]
2525
#[allow(dead_code, clippy::needless_pass_by_value, clippy::allow_attributes)]
26-
pub fn apply_fixes(source_text: String, fixes_json: String, eslint_compat: bool) -> Option<String> {
26+
pub fn apply_fixes(source_text: String, fixes_json: String) -> Option<String> {
2727
// Deserialize fixes JSON
2828
let fix_groups: Vec<Vec<JsFix>> = serde_json::from_str(&fixes_json).ok()?;
2929

@@ -47,11 +47,7 @@ pub fn apply_fixes(source_text: String, fixes_json: String, eslint_compat: bool)
4747
.collect::<Option<Vec<_>>>()?;
4848

4949
// Apply all the fixes
50-
let fixed_code = Fixer::new(&source_text, messages, None)
51-
.with_eslint_compat(eslint_compat)
52-
.fix()
53-
.fixed_code
54-
.into_owned();
50+
let fixed_code = Fixer::new(&source_text, messages, None).fix().fixed_code.into_owned();
5551

5652
Some(fixed_code)
5753
}

apps/oxlint/test/rule_tester.test.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,9 +1151,7 @@ describe("RuleTester", () => {
11511151
// Fix 1 replaces `a` (first char), fix 2 replaces `b` (second char).
11521152
// End of fix 1's range === start of fix 2's range.
11531153
//
1154-
// In standard mode, adjacent fixes are not considered overlapping, so both apply.
1155-
// In ESLint compat mode, adjacent fixes are considered overlapping (matching ESLint),
1156-
// so only the first fix applies.
1154+
// Adjacent fixes are considered overlapping, matching ESLint, so only the first fix applies.
11571155
const adjacentFixesRule: Rule = {
11581156
meta: {
11591157
fixable: "code",
@@ -1185,30 +1183,14 @@ describe("RuleTester", () => {
11851183
},
11861184
};
11871185

1188-
it("adjacent fixes applied in standard mode", () => {
1189-
const tester = new RuleTester();
1190-
tester.run("adjacent-fixes", adjacentFixesRule, {
1191-
valid: [],
1192-
invalid: [
1193-
{
1194-
code: "let ab;",
1195-
output: "let xy;",
1196-
errors: 2,
1197-
},
1198-
],
1199-
});
1200-
expect(runCases()).toEqual([null]);
1201-
});
1202-
1203-
it("only first adjacent fix applied in ESLint compat mode", () => {
1186+
it("only first adjacent fix applied", () => {
12041187
const tester = new RuleTester();
12051188
tester.run("adjacent-fixes", adjacentFixesRule, {
12061189
valid: [],
12071190
invalid: [
12081191
{
12091192
code: "let ab;",
12101193
output: "let xb;",
1211-
eslintCompat: true,
12121194
errors: 2,
12131195
},
12141196
],

crates/oxc_linter/src/fixer/mod.rs

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -319,12 +319,6 @@ pub struct Fixer<'a> {
319319
// The behavior is oriented by `oxlint` where only one PossibleFixes is applied.
320320
fix_index: u8,
321321

322-
/// When `true`, boundary-adjacent fixes (e.g. `[0,5]` and `[5,10]`) are considered
323-
/// overlapping, matching ESLint's `SourceCodeFixer` behavior.
324-
/// When `false`, only truly overlapping fixes are skipped.
325-
/// Defaults to `true`.
326-
eslint_compat: bool,
327-
328322
#[cfg(debug_assertions)]
329323
source_type: Option<SourceType>,
330324
}
@@ -341,7 +335,6 @@ impl<'a> Fixer<'a> {
341335
source_text,
342336
messages,
343337
fix_index: 0,
344-
eslint_compat: true,
345338
#[cfg(debug_assertions)]
346339
source_type,
347340
}
@@ -354,12 +347,6 @@ impl<'a> Fixer<'a> {
354347
self
355348
}
356349

357-
#[must_use]
358-
pub fn with_eslint_compat(mut self, eslint_compat: bool) -> Self {
359-
self.eslint_compat = eslint_compat;
360-
self
361-
}
362-
363350
/// # Panics
364351
pub fn fix(mut self) -> FixResult<'a> {
365352
let source_text = self.source_text;
@@ -375,7 +362,6 @@ impl<'a> Fixer<'a> {
375362
let mut fixed = false;
376363
let mut output = String::with_capacity(source_text.len());
377364
let mut last_pos: u32 = 0;
378-
let eslint_compat = self.eslint_compat;
379365

380366
// only keep messages that were not fixed
381367
let mut filtered_messages = Vec::with_capacity(self.messages.len());
@@ -400,16 +386,12 @@ impl<'a> Fixer<'a> {
400386
continue;
401387
}
402388

403-
// Skip fixes that overlap with a previously applied fix.
404-
//
405-
// In ESLint-compatible mode, boundary-adjacent fixes (e.g. [0, 5] and [5, 10]) are
406-
// considered overlapping. The legacy Oxlint mode only skips truly overlapping fixes.
407-
//
389+
// Skip fixes that overlap with a previously applied fix. Boundary-adjacent fixes
390+
// (e.g. [0, 5] and [5, 10]) are considered overlapping to match ESLint's behavior.
408391
// Never consider the first fix overlapping, because there's no previous fix to overlap with.
409392
// This extra check is required because `last_pos` is 0 initially, so a fix starting at offset 0
410-
// would incorrectly be considered as overlapping when `eslint_compat` is `true`.
411-
let overlaps =
412-
if eslint_compat && fixed { last_pos >= start } else { last_pos > start };
393+
// would incorrectly be considered as overlapping.
394+
let overlaps = fixed && last_pos >= start;
413395
if overlaps {
414396
filtered_messages.push(m);
415397
continue;
@@ -741,22 +723,6 @@ mod test {
741723
assert!(result.fixed);
742724
}
743725

744-
// In legacy Oxlint mode, fixes that share a boundary (end of one == start of next)
745-
// are not treated as overlapping. Both fixes are applied.
746-
#[test]
747-
fn apply_two_fix_when_the_start_the_same_as_the_previous_end_in_legacy_mode() {
748-
let messages = vec![
749-
create_message(remove_start(), PossibleFixes::Single(REMOVE_START)),
750-
create_message(replace_id(), PossibleFixes::Single(REPLACE_ID)),
751-
];
752-
let result = Fixer::new(TEST_CODE, messages, Some(SourceType::default()))
753-
.with_eslint_compat(false)
754-
.fix();
755-
assert_eq!(result.fixed_code, TEST_CODE.cow_replace("var answer", "foo"));
756-
assert_eq!(result.messages.len(), 0);
757-
assert!(result.fixed);
758-
}
759-
760726
#[test]
761727
fn apply_one_fix_when_range_overlap_and_one_message_has_no_fix() {
762728
let result = get_fix_result(vec![

0 commit comments

Comments
 (0)