mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 20:29:11 +00: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:
parent
196ceb76bb
commit
aead459fb2
10 changed files with 111 additions and 20 deletions
|
@ -234,11 +234,20 @@ export class Context {
|
||||||
const start = range[0];
|
const start = range[0];
|
||||||
const end = range[1];
|
const end = range[1];
|
||||||
|
|
||||||
let fix;
|
/** @type {Deno.lint.FixData[]} */
|
||||||
|
const fixes = [];
|
||||||
|
|
||||||
if (typeof data.fix === "function") {
|
if (typeof data.fix === "function") {
|
||||||
const fixer = new Fixer();
|
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(
|
doReport(
|
||||||
|
@ -247,7 +256,7 @@ export class Context {
|
||||||
data.hint,
|
data.hint,
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
fix,
|
fixes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ impl LintPluginContainer {
|
||||||
hint: Option<String>,
|
hint: Option<String>,
|
||||||
start_utf16: usize,
|
start_utf16: usize,
|
||||||
end_utf16: usize,
|
end_utf16: usize,
|
||||||
fix: Option<LintReportFix>,
|
raw_fixes: Vec<LintReportFix>,
|
||||||
) -> Result<(), LintReportError> {
|
) -> Result<(), LintReportError> {
|
||||||
fn out_of_range_err(
|
fn out_of_range_err(
|
||||||
map: &Utf16Map,
|
map: &Utf16Map,
|
||||||
|
@ -129,23 +129,27 @@ impl LintPluginContainer {
|
||||||
text_info: source_text_info.clone(),
|
text_info: source_text_info.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut fixes: Vec<LintFix> = vec![];
|
let changes = raw_fixes
|
||||||
|
.into_iter()
|
||||||
if let Some(fix) = fix {
|
.map(|fix| {
|
||||||
let fix_range = utf16_to_utf8_range(
|
let fix_range = utf16_to_utf8_range(
|
||||||
utf16_map,
|
utf16_map,
|
||||||
source_text_info,
|
source_text_info,
|
||||||
fix.range.0,
|
fix.range.0,
|
||||||
fix.range.1,
|
fix.range.1,
|
||||||
)?;
|
)?;
|
||||||
fixes.push(LintFix {
|
|
||||||
changes: vec![LintFixChange {
|
Ok(LintFixChange {
|
||||||
new_text: fix.text.into(),
|
new_text: fix.text.into(),
|
||||||
range: fix_range,
|
range: fix_range,
|
||||||
}],
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<LintFixChange>, LintReportError>>()?;
|
||||||
|
|
||||||
|
let fixes = vec![LintFix {
|
||||||
|
changes,
|
||||||
description: format!("Fix this {} problem", id).into(),
|
description: format!("Fix this {} problem", id).into(),
|
||||||
});
|
}];
|
||||||
}
|
|
||||||
|
|
||||||
let lint_diagnostic = LintDiagnostic {
|
let lint_diagnostic = LintDiagnostic {
|
||||||
specifier,
|
specifier,
|
||||||
|
@ -243,7 +247,7 @@ fn op_lint_report(
|
||||||
#[string] hint: Option<String>,
|
#[string] hint: Option<String>,
|
||||||
#[smi] start_utf16: usize,
|
#[smi] start_utf16: usize,
|
||||||
#[smi] end_utf16: usize,
|
#[smi] end_utf16: usize,
|
||||||
#[serde] fix: Option<LintReportFix>,
|
#[serde] fix: Vec<LintReportFix>,
|
||||||
) -> Result<(), LintReportError> {
|
) -> Result<(), LintReportError> {
|
||||||
let container = state.borrow_mut::<LintPluginContainer>();
|
let container = state.borrow_mut::<LintPluginContainer>();
|
||||||
container.report(id, message, hint, start_utf16, end_utf16, fix)?;
|
container.report(id, message, hint, start_utf16, end_utf16, fix)?;
|
||||||
|
|
2
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
2
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
|
@ -1388,7 +1388,7 @@ declare namespace Deno {
|
||||||
range?: Range;
|
range?: Range;
|
||||||
message: string;
|
message: string;
|
||||||
hint?: string;
|
hint?: string;
|
||||||
fix?(fixer: Fixer): FixData;
|
fix?(fixer: Fixer): FixData | Iterable<FixData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
13
tests/specs/lint/lint_plugin_multiple_fixes/__test__.jsonc
Normal file
13
tests/specs/lint/lint_plugin_multiple_fixes/__test__.jsonc
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"lint": {
|
||||||
|
"plugins": ["./plugin_arr.ts"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"lint": {
|
||||||
|
"plugins": ["./plugin_gen.ts"]
|
||||||
|
}
|
||||||
|
}
|
1
tests/specs/lint/lint_plugin_multiple_fixes/fix.out
Normal file
1
tests/specs/lint/lint_plugin_multiple_fixes/fix.out
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Checked 3 files
|
2
tests/specs/lint/lint_plugin_multiple_fixes/main.ts
Normal file
2
tests/specs/lint/lint_plugin_multiple_fixes/main.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const value = "unfixed";
|
||||||
|
console.log(value);
|
27
tests/specs/lint/lint_plugin_multiple_fixes/plugin_arr.ts
Normal file
27
tests/specs/lint/lint_plugin_multiple_fixes/plugin_arr.ts
Normal 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;
|
25
tests/specs/lint/lint_plugin_multiple_fixes/plugin_gen.ts
Normal file
25
tests/specs/lint/lint_plugin_multiple_fixes/plugin_gen.ts
Normal 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;
|
Loading…
Add table
Add a link
Reference in a new issue