add initial quick fix for utility conflict diagnostic
parent
b79dbfc9f9
commit
01941f967b
|
@ -22,7 +22,10 @@ import {
|
||||||
isInvalidApplyDiagnostic,
|
isInvalidApplyDiagnostic,
|
||||||
AugmentedDiagnostic,
|
AugmentedDiagnostic,
|
||||||
InvalidApplyDiagnostic,
|
InvalidApplyDiagnostic,
|
||||||
|
isUtilityConflictsDiagnostic,
|
||||||
|
UtilityConflictsDiagnostic,
|
||||||
} from '../diagnostics/types'
|
} from '../diagnostics/types'
|
||||||
|
import { flatten, dedupeBy } from '../../../util/array'
|
||||||
|
|
||||||
async function getDiagnosticsFromCodeActionParams(
|
async function getDiagnosticsFromCodeActionParams(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -35,7 +38,11 @@ async function getDiagnosticsFromCodeActionParams(
|
||||||
return params.context.diagnostics
|
return params.context.diagnostics
|
||||||
.map((diagnostic) => {
|
.map((diagnostic) => {
|
||||||
return diagnostics.find((d) => {
|
return diagnostics.find((d) => {
|
||||||
return rangesEqual(d.range, diagnostic.range)
|
return (
|
||||||
|
d.code === diagnostic.code &&
|
||||||
|
d.message === diagnostic.message &&
|
||||||
|
rangesEqual(d.range, diagnostic.range)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
@ -55,40 +62,46 @@ export async function provideCodeActions(
|
||||||
codes
|
codes
|
||||||
)
|
)
|
||||||
|
|
||||||
return Promise.all(
|
let actions = diagnostics.map((diagnostic) => {
|
||||||
diagnostics
|
if (isInvalidApplyDiagnostic(diagnostic)) {
|
||||||
.map((diagnostic) => {
|
return provideInvalidApplyCodeActions(state, params, diagnostic)
|
||||||
if (isInvalidApplyDiagnostic(diagnostic)) {
|
}
|
||||||
return provideInvalidApplyCodeAction(state, params, diagnostic)
|
|
||||||
}
|
|
||||||
|
|
||||||
let match = findLast(
|
if (isUtilityConflictsDiagnostic(diagnostic)) {
|
||||||
/ Did you mean (?:something like )?'(?<replacement>[^']+)'\?$/g,
|
return provideUtilityConflictsCodeActions(state, params, diagnostic)
|
||||||
diagnostic.message
|
}
|
||||||
)
|
|
||||||
|
|
||||||
if (!match) {
|
let match = findLast(
|
||||||
return null
|
/ Did you mean (?:something like )?'(?<replacement>[^']+)'\?$/g,
|
||||||
}
|
diagnostic.message
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
if (!match) {
|
||||||
title: `Replace with '${match.groups.replacement}'`,
|
return []
|
||||||
kind: CodeActionKind.QuickFix,
|
}
|
||||||
diagnostics: [diagnostic],
|
|
||||||
edit: {
|
return [
|
||||||
changes: {
|
{
|
||||||
[params.textDocument.uri]: [
|
title: `Replace with '${match.groups.replacement}'`,
|
||||||
{
|
kind: CodeActionKind.QuickFix,
|
||||||
range: diagnostic.range,
|
diagnostics: [diagnostic],
|
||||||
newText: match.groups.replacement,
|
edit: {
|
||||||
},
|
changes: {
|
||||||
],
|
[params.textDocument.uri]: [
|
||||||
},
|
{
|
||||||
|
range: diagnostic.range,
|
||||||
|
newText: match.groups.replacement,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
})
|
},
|
||||||
.filter(Boolean)
|
]
|
||||||
)
|
})
|
||||||
|
|
||||||
|
return Promise.all(actions)
|
||||||
|
.then(flatten)
|
||||||
|
.then((x) => dedupeBy(x, (item) => JSON.stringify(item.edit)))
|
||||||
}
|
}
|
||||||
|
|
||||||
function classNameToAst(
|
function classNameToAst(
|
||||||
|
@ -154,11 +167,56 @@ function classNameToAst(
|
||||||
return cssObjToAst(obj, state.modules.postcss)
|
return cssObjToAst(obj, state.modules.postcss)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function provideInvalidApplyCodeAction(
|
async function provideUtilityConflictsCodeActions(
|
||||||
|
state: State,
|
||||||
|
params: CodeActionParams,
|
||||||
|
diagnostic: UtilityConflictsDiagnostic
|
||||||
|
): Promise<CodeAction[]> {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: `Delete '${diagnostic.className.className}'`,
|
||||||
|
kind: CodeActionKind.QuickFix,
|
||||||
|
diagnostics: [diagnostic],
|
||||||
|
edit: {
|
||||||
|
changes: {
|
||||||
|
[params.textDocument.uri]: [
|
||||||
|
{
|
||||||
|
range: diagnostic.className.classList.range,
|
||||||
|
newText: removeRangeFromString(
|
||||||
|
diagnostic.className.classList.classList,
|
||||||
|
diagnostic.className.relativeRange
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `Delete '${diagnostic.otherClassName.className}'`,
|
||||||
|
kind: CodeActionKind.QuickFix,
|
||||||
|
diagnostics: [diagnostic],
|
||||||
|
edit: {
|
||||||
|
changes: {
|
||||||
|
[params.textDocument.uri]: [
|
||||||
|
{
|
||||||
|
range: diagnostic.className.classList.range,
|
||||||
|
newText: removeRangeFromString(
|
||||||
|
diagnostic.className.classList.classList,
|
||||||
|
diagnostic.otherClassName.relativeRange
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function provideInvalidApplyCodeActions(
|
||||||
state: State,
|
state: State,
|
||||||
params: CodeActionParams,
|
params: CodeActionParams,
|
||||||
diagnostic: InvalidApplyDiagnostic
|
diagnostic: InvalidApplyDiagnostic
|
||||||
): Promise<CodeAction> {
|
): Promise<CodeAction[]> {
|
||||||
let document = state.editor.documents.get(params.textDocument.uri)
|
let document = state.editor.documents.get(params.textDocument.uri)
|
||||||
let documentText = document.getText()
|
let documentText = document.getText()
|
||||||
const { postcss } = state.modules
|
const { postcss } = state.modules
|
||||||
|
@ -250,30 +308,32 @@ async function provideInvalidApplyCodeAction(
|
||||||
]).process(documentText, { from: undefined })
|
]).process(documentText, { from: undefined })
|
||||||
|
|
||||||
if (!change) {
|
if (!change) {
|
||||||
return null
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return [
|
||||||
title: 'Extract to new rule.',
|
{
|
||||||
kind: CodeActionKind.QuickFix,
|
title: 'Extract to new rule',
|
||||||
diagnostics: [diagnostic],
|
kind: CodeActionKind.QuickFix,
|
||||||
edit: {
|
diagnostics: [diagnostic],
|
||||||
changes: {
|
edit: {
|
||||||
[params.textDocument.uri]: [
|
changes: {
|
||||||
...(totalClassNamesInClassList > 1
|
[params.textDocument.uri]: [
|
||||||
? [
|
...(totalClassNamesInClassList > 1
|
||||||
{
|
? [
|
||||||
range: diagnostic.className.classList.range,
|
{
|
||||||
newText: removeRangeFromString(
|
range: diagnostic.className.classList.range,
|
||||||
diagnostic.className.classList.classList,
|
newText: removeRangeFromString(
|
||||||
diagnostic.className.relativeRange
|
diagnostic.className.classList.classList,
|
||||||
),
|
diagnostic.className.relativeRange
|
||||||
},
|
),
|
||||||
]
|
},
|
||||||
: []),
|
]
|
||||||
change,
|
: []),
|
||||||
],
|
change,
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,16 @@ export function dedupe<T>(arr: Array<T>): Array<T> {
|
||||||
return arr.filter((value, index, self) => self.indexOf(value) === index)
|
return arr.filter((value, index, self) => self.indexOf(value) === index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function dedupeBy<T>(
|
||||||
|
arr: Array<T>,
|
||||||
|
transform: (item: T) => any
|
||||||
|
): Array<T> {
|
||||||
|
return arr.filter(
|
||||||
|
(value, index, self) =>
|
||||||
|
self.map(transform).indexOf(transform(value)) === index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function ensureArray<T>(value: T | T[]): T[] {
|
export function ensureArray<T>(value: T | T[]): T[] {
|
||||||
return Array.isArray(value) ? value : [value]
|
return Array.isArray(value) ? value : [value]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue