consolidate conflict diagnostics and update quick fixes
parent
01941f967b
commit
7b916ab3c6
|
@ -11,7 +11,7 @@ import { isWithinRange } from '../../util/isWithinRange'
|
||||||
import { getClassNameParts } from '../../util/getClassNameAtPosition'
|
import { getClassNameParts } from '../../util/getClassNameAtPosition'
|
||||||
const dlv = require('dlv')
|
const dlv = require('dlv')
|
||||||
import dset from 'dset'
|
import dset from 'dset'
|
||||||
import { removeRangeFromString } from '../../util/removeRangeFromString'
|
import { removeRangesFromString } from '../../util/removeRangesFromString'
|
||||||
import detectIndent from 'detect-indent'
|
import detectIndent from 'detect-indent'
|
||||||
import { cssObjToAst } from '../../util/cssObjToAst'
|
import { cssObjToAst } from '../../util/cssObjToAst'
|
||||||
import isObject from '../../../util/isObject'
|
import isObject from '../../../util/isObject'
|
||||||
|
@ -26,6 +26,7 @@ import {
|
||||||
UtilityConflictsDiagnostic,
|
UtilityConflictsDiagnostic,
|
||||||
} from '../diagnostics/types'
|
} from '../diagnostics/types'
|
||||||
import { flatten, dedupeBy } from '../../../util/array'
|
import { flatten, dedupeBy } from '../../../util/array'
|
||||||
|
import { joinWithAnd } from '../../util/joinWithAnd'
|
||||||
|
|
||||||
async function getDiagnosticsFromCodeActionParams(
|
async function getDiagnosticsFromCodeActionParams(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -174,7 +175,11 @@ async function provideUtilityConflictsCodeActions(
|
||||||
): Promise<CodeAction[]> {
|
): Promise<CodeAction[]> {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: `Delete '${diagnostic.className.className}'`,
|
title: `Delete ${joinWithAnd(
|
||||||
|
diagnostic.otherClassNames.map(
|
||||||
|
(otherClassName) => `'${otherClassName.className}'`
|
||||||
|
)
|
||||||
|
)}`,
|
||||||
kind: CodeActionKind.QuickFix,
|
kind: CodeActionKind.QuickFix,
|
||||||
diagnostics: [diagnostic],
|
diagnostics: [diagnostic],
|
||||||
edit: {
|
edit: {
|
||||||
|
@ -182,27 +187,11 @@ async function provideUtilityConflictsCodeActions(
|
||||||
[params.textDocument.uri]: [
|
[params.textDocument.uri]: [
|
||||||
{
|
{
|
||||||
range: diagnostic.className.classList.range,
|
range: diagnostic.className.classList.range,
|
||||||
newText: removeRangeFromString(
|
newText: removeRangesFromString(
|
||||||
diagnostic.className.classList.classList,
|
diagnostic.className.classList.classList,
|
||||||
diagnostic.className.relativeRange
|
diagnostic.otherClassNames.map(
|
||||||
),
|
(otherClassName) => otherClassName.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
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -323,7 +312,7 @@ async function provideInvalidApplyCodeActions(
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
range: diagnostic.className.classList.range,
|
range: diagnostic.className.classList.range,
|
||||||
newText: removeRangeFromString(
|
newText: removeRangesFromString(
|
||||||
diagnostic.className.classList.classList,
|
diagnostic.className.classList.classList,
|
||||||
diagnostic.className.relativeRange
|
diagnostic.className.relativeRange
|
||||||
),
|
),
|
||||||
|
|
|
@ -29,6 +29,7 @@ import {
|
||||||
InvalidTailwindDirectiveDiagnostic,
|
InvalidTailwindDirectiveDiagnostic,
|
||||||
AugmentedDiagnostic,
|
AugmentedDiagnostic,
|
||||||
} from './types'
|
} from './types'
|
||||||
|
import { joinWithAnd } from '../../util/joinWithAnd'
|
||||||
|
|
||||||
function getInvalidApplyDiagnostics(
|
function getInvalidApplyDiagnostics(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -104,45 +105,58 @@ function getUtilityConflictDiagnostics(
|
||||||
const classNames = getClassNamesInClassList(classList)
|
const classNames = getClassNamesInClassList(classList)
|
||||||
|
|
||||||
classNames.forEach((className, index) => {
|
classNames.forEach((className, index) => {
|
||||||
|
let decls = getClassNameDecls(state, className.className)
|
||||||
|
if (!decls) return
|
||||||
|
|
||||||
|
let properties = Object.keys(decls)
|
||||||
|
let meta = getClassNameMeta(state, className.className)
|
||||||
|
|
||||||
let otherClassNames = classNames.filter((_className, i) => i !== index)
|
let otherClassNames = classNames.filter((_className, i) => i !== index)
|
||||||
otherClassNames.forEach((otherClassName) => {
|
|
||||||
let decls = getClassNameDecls(state, className.className)
|
|
||||||
if (!decls) return
|
|
||||||
|
|
||||||
|
let conflictingClassNames = otherClassNames.filter((otherClassName) => {
|
||||||
let otherDecls = getClassNameDecls(state, otherClassName.className)
|
let otherDecls = getClassNameDecls(state, otherClassName.className)
|
||||||
if (!otherDecls) return
|
if (!otherDecls) return false
|
||||||
|
|
||||||
let meta = getClassNameMeta(state, className.className)
|
|
||||||
let otherMeta = getClassNameMeta(state, otherClassName.className)
|
let otherMeta = getClassNameMeta(state, otherClassName.className)
|
||||||
|
|
||||||
if (
|
return (
|
||||||
equal(Object.keys(decls), Object.keys(otherDecls)) &&
|
equal(properties, Object.keys(otherDecls)) &&
|
||||||
!Array.isArray(meta) &&
|
!Array.isArray(meta) &&
|
||||||
!Array.isArray(otherMeta) &&
|
!Array.isArray(otherMeta) &&
|
||||||
equal(meta.context, otherMeta.context) &&
|
equal(meta.context, otherMeta.context) &&
|
||||||
equal(meta.pseudo, otherMeta.pseudo)
|
equal(meta.pseudo, otherMeta.pseudo)
|
||||||
) {
|
)
|
||||||
diagnostics.push({
|
})
|
||||||
code: DiagnosticKind.UtilityConflicts,
|
|
||||||
className,
|
if (conflictingClassNames.length === 0) return
|
||||||
otherClassName,
|
|
||||||
range: className.range,
|
diagnostics.push({
|
||||||
severity:
|
code: DiagnosticKind.UtilityConflicts,
|
||||||
severity === 'error'
|
className,
|
||||||
? DiagnosticSeverity.Error
|
otherClassNames: conflictingClassNames,
|
||||||
: DiagnosticSeverity.Warning,
|
range: className.range,
|
||||||
message: `'${className.className}' and '${otherClassName.className}' apply the same CSS properties.`,
|
severity:
|
||||||
relatedInformation: [
|
severity === 'error'
|
||||||
{
|
? DiagnosticSeverity.Error
|
||||||
message: otherClassName.className,
|
: DiagnosticSeverity.Warning,
|
||||||
location: {
|
message: `'${className.className}' applies the same CSS ${
|
||||||
uri: document.uri,
|
properties.length === 1 ? 'property' : 'properties'
|
||||||
range: otherClassName.range,
|
} as ${joinWithAnd(
|
||||||
},
|
conflictingClassNames.map(
|
||||||
|
(conflictingClassName) => `'${conflictingClassName.className}'`
|
||||||
|
)
|
||||||
|
)}.`,
|
||||||
|
relatedInformation: conflictingClassNames.map(
|
||||||
|
(conflictingClassName) => {
|
||||||
|
return {
|
||||||
|
message: conflictingClassName.className,
|
||||||
|
location: {
|
||||||
|
uri: document.uri,
|
||||||
|
range: conflictingClassName.range,
|
||||||
},
|
},
|
||||||
],
|
}
|
||||||
})
|
}
|
||||||
}
|
),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,7 +13,7 @@ export enum DiagnosticKind {
|
||||||
export type UtilityConflictsDiagnostic = Diagnostic & {
|
export type UtilityConflictsDiagnostic = Diagnostic & {
|
||||||
code: DiagnosticKind.UtilityConflicts
|
code: DiagnosticKind.UtilityConflicts
|
||||||
className: DocumentClassName
|
className: DocumentClassName
|
||||||
otherClassName: DocumentClassName
|
otherClassNames: DocumentClassName[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isUtilityConflictsDiagnostic(
|
export function isUtilityConflictsDiagnostic(
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export function joinWithAnd(strings: string[]): string {
|
||||||
|
return strings.reduce((acc, cur, i) => {
|
||||||
|
if (i === 0) {
|
||||||
|
return cur
|
||||||
|
}
|
||||||
|
if (strings.length > 1 && i === strings.length - 1) {
|
||||||
|
return `${acc} and ${cur}`
|
||||||
|
}
|
||||||
|
return `${acc}, ${cur}`
|
||||||
|
}, '')
|
||||||
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
import { Range } from 'vscode-languageserver'
|
|
||||||
import lineColumn from 'line-column'
|
|
||||||
|
|
||||||
export function removeRangeFromString(str: string, range: Range): string {
|
|
||||||
let finder = lineColumn(str + '\n', { origin: 0 })
|
|
||||||
let start = finder.toIndex(range.start.line, range.start.character)
|
|
||||||
let end = finder.toIndex(range.end.line, range.end.character)
|
|
||||||
for (let i = start - 1; i >= 0; i--) {
|
|
||||||
if (/\s/.test(str.charAt(i))) {
|
|
||||||
start = i
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (str.substr(0, start) + str.substr(end)).trim()
|
|
||||||
}
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { Range } from 'vscode-languageserver'
|
||||||
|
import lineColumn from 'line-column'
|
||||||
|
import { ensureArray } from '../../util/array'
|
||||||
|
|
||||||
|
export function removeRangesFromString(
|
||||||
|
str: string,
|
||||||
|
rangeOrRanges: Range | Range[]
|
||||||
|
): string {
|
||||||
|
let ranges = ensureArray(rangeOrRanges)
|
||||||
|
let finder = lineColumn(str + '\n', { origin: 0 })
|
||||||
|
let indexRanges: { start: number; end: number }[] = []
|
||||||
|
|
||||||
|
ranges.forEach((range) => {
|
||||||
|
let start = finder.toIndex(range.start.line, range.start.character)
|
||||||
|
let end = finder.toIndex(range.end.line, range.end.character)
|
||||||
|
for (let i = start - 1; i >= 0; i--) {
|
||||||
|
if (/\s/.test(str.charAt(i))) {
|
||||||
|
start = i
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indexRanges.push({ start, end })
|
||||||
|
})
|
||||||
|
|
||||||
|
indexRanges.sort((a, b) => a.start - b.start)
|
||||||
|
|
||||||
|
let result = ''
|
||||||
|
let i = 0
|
||||||
|
|
||||||
|
indexRanges.forEach((indexRange) => {
|
||||||
|
result += str.substring(i, indexRange.start)
|
||||||
|
i = indexRange.end
|
||||||
|
})
|
||||||
|
|
||||||
|
result += str.substring(i)
|
||||||
|
|
||||||
|
return result.trim()
|
||||||
|
}
|
Loading…
Reference in New Issue