Skip to content

Commit 2c7a89b

Browse files
committed
Refactor
1 parent 4f7c0e4 commit 2c7a89b

File tree

2 files changed

+73
-54
lines changed

2 files changed

+73
-54
lines changed

packages/tailwindcss-language-server/src/language/css-server.ts

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { Utils, URI } from 'vscode-uri'
1818
import { getLanguageModelCache } from './languageModelCache'
1919
import { Stylesheet } from 'vscode-css-languageservice'
2020
import dlv from 'dlv'
21+
import { rewriteCss } from './rewriting'
2122

2223
export class CssServer {
2324
private documents: TextDocuments<TextDocument>
@@ -332,61 +333,8 @@ export class CssServer {
332333
}, validationDelayMs)
333334
}
334335

335-
function replace(delta = 0) {
336-
return (_match: string, p1: string) => {
337-
let lines = p1.split('\n')
338-
if (lines.length > 1) {
339-
return `@media(${MEDIA_MARKER})${'\n'.repeat(lines.length - 1)}${' '.repeat(
340-
lines[lines.length - 1].length,
341-
)}{`
342-
}
343-
return `@media(${MEDIA_MARKER})${' '.repeat(p1.length + delta)}{`
344-
}
345-
}
346-
function replaceWithStyleRule(delta = 0) {
347-
return (_match: string, p1: string) => {
348-
let spaces = ' '.repeat(p1.length + delta)
349-
return `.placeholder${spaces}{`
350-
}
351-
}
352-
353336
function createVirtualCssDocument(textDocument: TextDocument): TextDocument {
354-
let content = textDocument
355-
.getText()
356-
357-
// Remove inline `@layer` directives
358-
// TODO: This should be unnecessary once we have updated the bundled CSS
359-
// language service
360-
.replace(/@layer\s+[^;{]+(;|$)/g, '')
361-
362-
.replace(/@screen(\s+[^{]+){/g, replace(-2))
363-
.replace(/@variants(\s+[^{]+){/g, replace())
364-
.replace(/@responsive(\s*){/g, replace())
365-
.replace(/@utility(\s+[^{]+){/g, replaceWithStyleRule())
366-
.replace(/@custom-variant(\s+[^;{]+);/g, (match: string) => {
367-
let spaces = ' '.repeat(match.length - 11)
368-
return `@media (${MEDIA_MARKER})${spaces}{}`
369-
})
370-
.replace(/@custom-variant(\s+[^{]+){/g, replaceWithStyleRule())
371-
.replace(/@variant(\s+[^{]+){/g, replaceWithStyleRule())
372-
.replace(/@layer(\s+[^{]{2,}){/g, replace(-3))
373-
.replace(/@reference\s*([^;]{2,})/g, '@import $1')
374-
.replace(
375-
/@media(\s+screen\s*\([^)]+\))/g,
376-
(_match, screen) => `@media (${MEDIA_MARKER})${' '.repeat(screen.length - 4)}`,
377-
)
378-
.replace(
379-
/@import(\s*)("(?:[^"]+)"|'(?:[^']+)')\s*(.*?)(?=;|$)/g,
380-
(_match, spaces, url, other) => {
381-
// Remove`source(…)`, `theme(…)`, and `prefix(…)` from `@import`s
382-
// otherwise we'll show syntax-error diagnostics which we don't want
383-
other = other.replace(/((source|theme|prefix)\([^)]+\)\s*)+?/g, '')
384-
385-
// We have to add the spaces here so the character positions line up
386-
return `@import${spaces}"${url.slice(1, -1)}" ${other}`
387-
},
388-
)
389-
.replace(/(?<=\b(?:theme|config)\([^)]*)[.[\]]/g, '_')
337+
let content = rewriteCss(textDocument.getText())
390338

391339
return TextDocument.create(
392340
textDocument.uri,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
const MEDIA_MARKER = '℘'
2+
3+
function replaceWithAtRule(delta = 0) {
4+
return (_match: string, p1: string) => {
5+
let lines = p1.split('\n')
6+
if (lines.length > 1) {
7+
return `@media(${MEDIA_MARKER})${'\n'.repeat(lines.length - 1)}${' '.repeat(
8+
lines[lines.length - 1].length,
9+
)}{`
10+
}
11+
12+
return `@media(${MEDIA_MARKER})${' '.repeat(p1.length + delta)}{`
13+
}
14+
}
15+
16+
function replaceWithStyleRule(delta = 0) {
17+
return (_match: string, p1: string) => {
18+
let spaces = ' '.repeat(p1.length + delta)
19+
return `.placeholder${spaces}{`
20+
}
21+
}
22+
23+
/**
24+
* Rewrites the given CSS to be more compatible with the CSS language service
25+
*
26+
* The VSCode CSS language service doesn't understand our custom at-rules, nor
27+
* our custom functions and minor syntax tweaks. This means it will show syntax
28+
* errors for things that aren't actually errors.
29+
*/
30+
export function rewriteCss(css: string) {
31+
// Remove inline `@layer` directives
32+
// TODO: This should be unnecessary once we have updated the bundled CSS
33+
// language service
34+
css = css.replace(/@layer\s+[^;{]+(;|$)/g, '')
35+
36+
css = css.replace(/@screen(\s+[^{]+){/g, replaceWithAtRule(-2))
37+
css = css.replace(/@variants(\s+[^{]+){/g, replaceWithAtRule())
38+
css = css.replace(/@responsive(\s*){/g, replaceWithAtRule())
39+
css = css.replace(/@utility(\s+[^{]+){/g, replaceWithStyleRule())
40+
41+
css = css.replace(/@custom-variant(\s+[^;{]+);/g, (match: string) => {
42+
let spaces = ' '.repeat(match.length - 11)
43+
return `@media (${MEDIA_MARKER})${spaces}{}`
44+
})
45+
46+
css = css.replace(/@custom-variant(\s+[^{]+){/g, replaceWithStyleRule())
47+
css = css.replace(/@variant(\s+[^{]+){/g, replaceWithStyleRule())
48+
css = css.replace(/@layer(\s+[^{]{2,}){/g, replaceWithAtRule(-3))
49+
css = css.replace(/@reference\s*([^;]{2,})/g, '@import $1')
50+
51+
css = css.replace(
52+
/@media(\s+screen\s*\([^)]+\))/g,
53+
(_match, screen) => `@media (${MEDIA_MARKER})${' '.repeat(screen.length - 4)}`,
54+
)
55+
56+
css = css.replace(
57+
/@import(\s*)("(?:[^"]+)"|'(?:[^']+)')\s*(.*?)(?=;|$)/g,
58+
(_match, spaces, url, other) => {
59+
// Remove`source(…)`, `theme(…)`, and `prefix(…)` from `@import`s
60+
// otherwise we'll show syntax-error diagnostics which we don't want
61+
other = other.replace(/((source|theme|prefix)\([^)]+\)\s*)+?/g, '')
62+
63+
// We have to add the spaces here so the character positions line up
64+
return `@import${spaces}"${url.slice(1, -1)}" ${other}`
65+
},
66+
)
67+
68+
css = css.replace(/(?<=\b(?:theme|config)\([^)]*)[.[\]]/g, '_')
69+
70+
return css
71+
}

0 commit comments

Comments
 (0)