Skip to content

Commit 9b47dd0

Browse files
authored
Fix CSS conflict diagnostics in semicolonless CSS documents (#771)
1 parent 8266d6b commit 9b47dd0

File tree

3 files changed

+29
-14
lines changed

3 files changed

+29
-14
lines changed

packages/tailwindcss-language-service/src/diagnostics/getInvalidTailwindDirectiveDiagnostics.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as semver from '../util/semver'
88
import { closest } from '../util/closest'
99
import { absoluteRange } from '../util/absoluteRange'
1010
import { getTextWithoutComments } from '../util/doc'
11+
import { isSemicolonlessCssLanguage } from '../util/languages'
1112

1213
export function getInvalidTailwindDirectiveDiagnostics(
1314
state: State,
@@ -28,13 +29,8 @@ export function getInvalidTailwindDirectiveDiagnostics(
2829
ranges.push(...boundaries.filter((b) => b.type === 'css').map(({ range }) => range))
2930
}
3031

31-
let notSemicolonLanguages = ['sass', 'sugarss', 'stylus']
3232
let regex: RegExp
33-
if (
34-
notSemicolonLanguages.includes(document.languageId) ||
35-
(state.editor &&
36-
notSemicolonLanguages.includes(state.editor.userLanguages[document.languageId]))
37-
) {
33+
if (isSemicolonlessCssLanguage(document.languageId, state.editor?.userLanguages)) {
3834
regex = /(?:\s|^)@tailwind\s+(?<value>[^\r\n]+)/g
3935
} else {
4036
regex = /(?:\s|^)@tailwind\s+(?<value>[^;]+)/g

packages/tailwindcss-language-service/src/util/find.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { getLanguageBoundaries } from './getLanguageBoundaries'
1111
import { resolveRange } from './resolveRange'
1212
import Regex from 'becke-ch--regex--s0-0-v1--base--pl--lib'
1313
import { getTextWithoutComments } from './doc'
14+
import { isSemicolonlessCssLanguage } from './languages'
1415

1516
export function findAll(re: RegExp, str: string): RegExpMatchArray[] {
1617
let match: RegExpMatchArray
@@ -91,12 +92,16 @@ export async function findClassNamesInDocument(
9192
)
9293
}
9394

94-
export function findClassListsInCssRange(doc: TextDocument, range?: Range): DocumentClassList[] {
95+
export function findClassListsInCssRange(
96+
state: State,
97+
doc: TextDocument,
98+
range?: Range
99+
): DocumentClassList[] {
95100
const text = getTextWithoutComments(doc, 'css', range)
96-
const matches = findAll(
97-
/(@apply\s+)(?<classList>[^;}]+?)(?<important>\s*!important)?\s*[;}]/g,
98-
text
99-
)
101+
let regex = isSemicolonlessCssLanguage(doc.languageId, state.editor?.userLanguages)
102+
? /(@apply\s+)(?<classList>[^}\r\n]+?)(?<important>\s*!important)?(?:\r|\n|}|$)/g
103+
: /(@apply\s+)(?<classList>[^;}]+?)(?<important>\s*!important)?\s*[;}]/g
104+
const matches = findAll(regex, text)
100105
const globalStart: Position = range ? range.start : { line: 0, character: 0 }
101106

102107
return matches.map((match) => {
@@ -292,7 +297,7 @@ export async function findClassListsInRange(
292297
): Promise<DocumentClassList[]> {
293298
let classLists: DocumentClassList[]
294299
if (mode === 'css') {
295-
classLists = findClassListsInCssRange(doc, range)
300+
classLists = findClassListsInCssRange(state, doc, range)
296301
} else {
297302
classLists = await findClassListsInHtmlRange(state, doc, mode, range)
298303
}
@@ -307,7 +312,7 @@ export async function findClassListsInDocument(
307312
doc: TextDocument
308313
): Promise<DocumentClassList[]> {
309314
if (isCssDoc(state, doc)) {
310-
return findClassListsInCssRange(doc)
315+
return findClassListsInCssRange(state, doc)
311316
}
312317

313318
let boundaries = getLanguageBoundaries(state, doc)
@@ -324,7 +329,7 @@ export async function findClassListsInDocument(
324329
)),
325330
...boundaries
326331
.filter((b) => b.type === 'css')
327-
.map(({ range }) => findClassListsInCssRange(doc, range)),
332+
.map(({ range }) => findClassListsInCssRange(state, doc, range)),
328333
await findCustomClassLists(state, doc),
329334
])
330335
)

packages/tailwindcss-language-service/src/util/languages.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { EditorState } from './state'
2+
13
export const htmlLanguages = [
24
'aspnetcorerazor',
35
'astro',
@@ -57,3 +59,15 @@ export const jsLanguages = [
5759
export const specialLanguages = ['vue', 'svelte']
5860

5961
export const languages = [...cssLanguages, ...htmlLanguages, ...jsLanguages, ...specialLanguages]
62+
63+
const semicolonlessLanguages = ['sass', 'sugarss', 'stylus']
64+
65+
export function isSemicolonlessCssLanguage(
66+
languageId: string,
67+
userLanguages: EditorState['userLanguages'] = {}
68+
) {
69+
return (
70+
semicolonlessLanguages.includes(languageId) ||
71+
semicolonlessLanguages.includes(userLanguages[languageId])
72+
)
73+
}

0 commit comments

Comments
 (0)