0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 17:34:47 -05:00

feat(unstable): support multiple fixes from lint plugins (#28040)

This PR supports returning multiple changes from a lint fix. It works
the same way as eslint, see
https://eslint.org/docs/latest/extend/custom-rules#applying-fixes .

- Return a single fix
- Return an array of fixes
- Return a generator function with fixes
This commit is contained in:
Marvin Hagemeister 2025-02-11 15:24:28 +01:00 committed by GitHub
parent 196ceb76bb
commit aead459fb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 111 additions and 20 deletions

View file

@ -234,11 +234,20 @@ export class Context {
const start = range[0];
const end = range[1];
let fix;
/** @type {Deno.lint.FixData[]} */
const fixes = [];
if (typeof data.fix === "function") {
const fixer = new Fixer();
fix = data.fix(fixer);
const result = data.fix(fixer);
if (Symbol.iterator in result) {
for (const fix of result) {
fixes.push(fix);
}
} else {
fixes.push(result);
}
}
doReport(
@ -247,7 +256,7 @@ export class Context {
data.hint,
start,
end,
fix,
fixes,
);
}
}

View file

@ -82,7 +82,7 @@ impl LintPluginContainer {
hint: Option<String>,
start_utf16: usize,
end_utf16: usize,
fix: Option<LintReportFix>,
raw_fixes: Vec<LintReportFix>,
) -> Result<(), LintReportError> {
fn out_of_range_err(
map: &Utf16Map,
@ -129,23 +129,27 @@ impl LintPluginContainer {
text_info: source_text_info.clone(),
};
let mut fixes: Vec<LintFix> = vec![];
let changes = raw_fixes
.into_iter()
.map(|fix| {
let fix_range = utf16_to_utf8_range(
utf16_map,
source_text_info,
fix.range.0,
fix.range.1,
)?;
if let Some(fix) = fix {
let fix_range = utf16_to_utf8_range(
utf16_map,
source_text_info,
fix.range.0,
fix.range.1,
)?;
fixes.push(LintFix {
changes: vec![LintFixChange {
Ok(LintFixChange {
new_text: fix.text.into(),
range: fix_range,
}],
description: format!("Fix this {} problem", id).into(),
});
}
})
})
.collect::<Result<Vec<LintFixChange>, LintReportError>>()?;
let fixes = vec![LintFix {
changes,
description: format!("Fix this {} problem", id).into(),
}];
let lint_diagnostic = LintDiagnostic {
specifier,
@ -243,7 +247,7 @@ fn op_lint_report(
#[string] hint: Option<String>,
#[smi] start_utf16: usize,
#[smi] end_utf16: usize,
#[serde] fix: Option<LintReportFix>,
#[serde] fix: Vec<LintReportFix>,
) -> Result<(), LintReportError> {
let container = state.borrow_mut::<LintPluginContainer>();
container.report(id, message, hint, start_utf16, end_utf16, fix)?;

View file

@ -1388,7 +1388,7 @@ declare namespace Deno {
range?: Range;
message: string;
hint?: string;
fix?(fixer: Fixer): FixData;
fix?(fixer: Fixer): FixData | Iterable<FixData>;
}
/**

View file

@ -0,0 +1,13 @@
{
"tempDir": true,
"steps": [
{
"args": "lint --config=deno_gen.json --fix",
"output": "fix.out"
},
{
"args": "lint --config=deno_arr.json --fix",
"output": "fix.out"
}
]
}

View file

@ -0,0 +1,5 @@
{
"lint": {
"plugins": ["./plugin_arr.ts"]
}
}

View file

@ -0,0 +1,5 @@
{
"lint": {
"plugins": ["./plugin_gen.ts"]
}
}

View file

@ -0,0 +1 @@
Checked 3 files

View file

@ -0,0 +1,2 @@
const value = "unfixed";
console.log(value);

View file

@ -0,0 +1,27 @@
export default {
name: "test-plugin",
rules: {
"my-rule": {
create(context) {
return {
VariableDeclarator(node) {
if (
node.init?.type === "Literal" && node.init.value === "unfixed"
) {
context.report({
node: node.init!,
message: 'should be "bar" + have string type',
fix(fixer) {
return [
fixer.insertTextAfter(node.id, ": string"),
fixer.replaceText(node.init!, '"bar"'),
];
},
});
}
},
};
},
},
},
} satisfies Deno.lint.Plugin;

View file

@ -0,0 +1,25 @@
export default {
name: "test-plugin",
rules: {
"my-rule": {
create(context) {
return {
VariableDeclarator(node) {
if (
node.init?.type === "Literal" && node.init.value === "unfixed"
) {
context.report({
node: node.init!,
message: 'should be "bar" + have string type',
*fix(fixer) {
yield fixer.insertTextAfter(node.id, ": string");
yield fixer.replaceText(node.init!, '"bar"');
},
});
}
},
};
},
},
},
} satisfies Deno.lint.Plugin;