Fix CSS conflict diagnostics in semicolonless CSS documents (#771)
parent
8266d6b0aa
commit
9b47dd0597
|
@ -8,6 +8,7 @@ import * as semver from '../util/semver'
|
||||||
import { closest } from '../util/closest'
|
import { closest } from '../util/closest'
|
||||||
import { absoluteRange } from '../util/absoluteRange'
|
import { absoluteRange } from '../util/absoluteRange'
|
||||||
import { getTextWithoutComments } from '../util/doc'
|
import { getTextWithoutComments } from '../util/doc'
|
||||||
|
import { isSemicolonlessCssLanguage } from '../util/languages'
|
||||||
|
|
||||||
export function getInvalidTailwindDirectiveDiagnostics(
|
export function getInvalidTailwindDirectiveDiagnostics(
|
||||||
state: State,
|
state: State,
|
||||||
|
@ -28,13 +29,8 @@ export function getInvalidTailwindDirectiveDiagnostics(
|
||||||
ranges.push(...boundaries.filter((b) => b.type === 'css').map(({ range }) => range))
|
ranges.push(...boundaries.filter((b) => b.type === 'css').map(({ range }) => range))
|
||||||
}
|
}
|
||||||
|
|
||||||
let notSemicolonLanguages = ['sass', 'sugarss', 'stylus']
|
|
||||||
let regex: RegExp
|
let regex: RegExp
|
||||||
if (
|
if (isSemicolonlessCssLanguage(document.languageId, state.editor?.userLanguages)) {
|
||||||
notSemicolonLanguages.includes(document.languageId) ||
|
|
||||||
(state.editor &&
|
|
||||||
notSemicolonLanguages.includes(state.editor.userLanguages[document.languageId]))
|
|
||||||
) {
|
|
||||||
regex = /(?:\s|^)@tailwind\s+(?<value>[^\r\n]+)/g
|
regex = /(?:\s|^)@tailwind\s+(?<value>[^\r\n]+)/g
|
||||||
} else {
|
} else {
|
||||||
regex = /(?:\s|^)@tailwind\s+(?<value>[^;]+)/g
|
regex = /(?:\s|^)@tailwind\s+(?<value>[^;]+)/g
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { getLanguageBoundaries } from './getLanguageBoundaries'
|
||||||
import { resolveRange } from './resolveRange'
|
import { resolveRange } from './resolveRange'
|
||||||
import Regex from 'becke-ch--regex--s0-0-v1--base--pl--lib'
|
import Regex from 'becke-ch--regex--s0-0-v1--base--pl--lib'
|
||||||
import { getTextWithoutComments } from './doc'
|
import { getTextWithoutComments } from './doc'
|
||||||
|
import { isSemicolonlessCssLanguage } from './languages'
|
||||||
|
|
||||||
export function findAll(re: RegExp, str: string): RegExpMatchArray[] {
|
export function findAll(re: RegExp, str: string): RegExpMatchArray[] {
|
||||||
let match: RegExpMatchArray
|
let match: RegExpMatchArray
|
||||||
|
@ -91,12 +92,16 @@ export async function findClassNamesInDocument(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findClassListsInCssRange(doc: TextDocument, range?: Range): DocumentClassList[] {
|
export function findClassListsInCssRange(
|
||||||
|
state: State,
|
||||||
|
doc: TextDocument,
|
||||||
|
range?: Range
|
||||||
|
): DocumentClassList[] {
|
||||||
const text = getTextWithoutComments(doc, 'css', range)
|
const text = getTextWithoutComments(doc, 'css', range)
|
||||||
const matches = findAll(
|
let regex = isSemicolonlessCssLanguage(doc.languageId, state.editor?.userLanguages)
|
||||||
/(@apply\s+)(?<classList>[^;}]+?)(?<important>\s*!important)?\s*[;}]/g,
|
? /(@apply\s+)(?<classList>[^}\r\n]+?)(?<important>\s*!important)?(?:\r|\n|}|$)/g
|
||||||
text
|
: /(@apply\s+)(?<classList>[^;}]+?)(?<important>\s*!important)?\s*[;}]/g
|
||||||
)
|
const matches = findAll(regex, text)
|
||||||
const globalStart: Position = range ? range.start : { line: 0, character: 0 }
|
const globalStart: Position = range ? range.start : { line: 0, character: 0 }
|
||||||
|
|
||||||
return matches.map((match) => {
|
return matches.map((match) => {
|
||||||
|
@ -292,7 +297,7 @@ export async function findClassListsInRange(
|
||||||
): Promise<DocumentClassList[]> {
|
): Promise<DocumentClassList[]> {
|
||||||
let classLists: DocumentClassList[]
|
let classLists: DocumentClassList[]
|
||||||
if (mode === 'css') {
|
if (mode === 'css') {
|
||||||
classLists = findClassListsInCssRange(doc, range)
|
classLists = findClassListsInCssRange(state, doc, range)
|
||||||
} else {
|
} else {
|
||||||
classLists = await findClassListsInHtmlRange(state, doc, mode, range)
|
classLists = await findClassListsInHtmlRange(state, doc, mode, range)
|
||||||
}
|
}
|
||||||
|
@ -307,7 +312,7 @@ export async function findClassListsInDocument(
|
||||||
doc: TextDocument
|
doc: TextDocument
|
||||||
): Promise<DocumentClassList[]> {
|
): Promise<DocumentClassList[]> {
|
||||||
if (isCssDoc(state, doc)) {
|
if (isCssDoc(state, doc)) {
|
||||||
return findClassListsInCssRange(doc)
|
return findClassListsInCssRange(state, doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
let boundaries = getLanguageBoundaries(state, doc)
|
let boundaries = getLanguageBoundaries(state, doc)
|
||||||
|
@ -324,7 +329,7 @@ export async function findClassListsInDocument(
|
||||||
)),
|
)),
|
||||||
...boundaries
|
...boundaries
|
||||||
.filter((b) => b.type === 'css')
|
.filter((b) => b.type === 'css')
|
||||||
.map(({ range }) => findClassListsInCssRange(doc, range)),
|
.map(({ range }) => findClassListsInCssRange(state, doc, range)),
|
||||||
await findCustomClassLists(state, doc),
|
await findCustomClassLists(state, doc),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import type { EditorState } from './state'
|
||||||
|
|
||||||
export const htmlLanguages = [
|
export const htmlLanguages = [
|
||||||
'aspnetcorerazor',
|
'aspnetcorerazor',
|
||||||
'astro',
|
'astro',
|
||||||
|
@ -57,3 +59,15 @@ export const jsLanguages = [
|
||||||
export const specialLanguages = ['vue', 'svelte']
|
export const specialLanguages = ['vue', 'svelte']
|
||||||
|
|
||||||
export const languages = [...cssLanguages, ...htmlLanguages, ...jsLanguages, ...specialLanguages]
|
export const languages = [...cssLanguages, ...htmlLanguages, ...jsLanguages, ...specialLanguages]
|
||||||
|
|
||||||
|
const semicolonlessLanguages = ['sass', 'sugarss', 'stylus']
|
||||||
|
|
||||||
|
export function isSemicolonlessCssLanguage(
|
||||||
|
languageId: string,
|
||||||
|
userLanguages: EditorState['userLanguages'] = {}
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
semicolonlessLanguages.includes(languageId) ||
|
||||||
|
semicolonlessLanguages.includes(userLanguages[languageId])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue