Skip to content

Commit 2672c70

Browse files
committed
Add diagnostics for invalid uses of source(…) and @source
1 parent 341a9ff commit 2672c70

File tree

7 files changed

+444
-0
lines changed

7 files changed

+444
-0
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function getDefaultSettings(): Settings {
2727
invalidVariant: 'error',
2828
invalidConfigPath: 'error',
2929
invalidTailwindDirective: 'error',
30+
invalidSourceDirective: 'error',
3031
recommendedVariantOrder: 'warning',
3132
},
3233
showPixelEquivalents: true,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import { expect, test } from 'vitest'
2+
import { withFixture } from '../common'
3+
4+
const css = String.raw
5+
6+
withFixture('v4/basic', (c) => {
7+
function runTest(name, { code, expected, language }) {
8+
test(name, async () => {
9+
let promise = new Promise((resolve) => {
10+
c.onNotification('textDocument/publishDiagnostics', ({ diagnostics }) => {
11+
resolve(diagnostics)
12+
})
13+
})
14+
15+
let doc = await c.openDocument({ text: code, lang: language })
16+
let diagnostics = await promise
17+
18+
expected = JSON.parse(JSON.stringify(expected).replaceAll('{{URI}}', doc.uri))
19+
20+
expect(diagnostics).toMatchObject(expected)
21+
})
22+
}
23+
24+
runTest('Source directives require paths', {
25+
language: 'css',
26+
code: `
27+
@import 'tailwindcss' source();
28+
@import 'tailwindcss' source('');
29+
@import 'tailwindcss' source("");
30+
@tailwind utilities source();
31+
@tailwind utilities source('');
32+
@tailwind utilities source("");
33+
`,
34+
expected: [
35+
{
36+
code: 'invalidSourceDirective',
37+
message: 'Need a path for the source directive',
38+
range: {
39+
start: { line: 1, character: 35 },
40+
end: { line: 1, character: 35 },
41+
},
42+
},
43+
{
44+
code: 'invalidSourceDirective',
45+
message: 'Need a path for the source directive',
46+
range: {
47+
start: { line: 2, character: 35 },
48+
end: { line: 2, character: 37 },
49+
},
50+
},
51+
{
52+
code: 'invalidSourceDirective',
53+
message: 'Need a path for the source directive',
54+
range: {
55+
start: { line: 3, character: 35 },
56+
end: { line: 3, character: 37 },
57+
},
58+
},
59+
{
60+
code: 'invalidSourceDirective',
61+
message: 'Need a path for the source directive',
62+
range: {
63+
start: { line: 4, character: 33 },
64+
end: { line: 4, character: 33 },
65+
},
66+
},
67+
{
68+
code: 'invalidSourceDirective',
69+
message: 'Need a path for the source directive',
70+
range: {
71+
start: { line: 5, character: 33 },
72+
end: { line: 5, character: 35 },
73+
},
74+
},
75+
{
76+
code: 'invalidSourceDirective',
77+
message: 'Need a path for the source directive',
78+
range: {
79+
start: { line: 6, character: 33 },
80+
end: { line: 6, character: 35 },
81+
},
82+
},
83+
],
84+
})
85+
86+
runTest('source(none) must not be mispelled', {
87+
language: 'css',
88+
code: `
89+
@import 'tailwindcss' source(no);
90+
@tailwind utilities source(no);
91+
`,
92+
expected: [
93+
{
94+
code: 'invalidSourceDirective',
95+
message: '`source(no)` is invalid. Did you mean `source(none)`.',
96+
range: {
97+
start: { line: 1, character: 35 },
98+
end: { line: 1, character: 37 },
99+
},
100+
},
101+
{
102+
code: 'invalidSourceDirective',
103+
message: '`source(no)` is invalid. Did you mean `source(none)`.',
104+
range: {
105+
start: { line: 2, character: 33 },
106+
end: { line: 2, character: 35 },
107+
},
108+
},
109+
],
110+
})
111+
112+
runTest('source("…") does not produce diagnostics', {
113+
language: 'css',
114+
code: `
115+
@import 'tailwindcss' source('../app');
116+
@tailwind utilities source('../app');
117+
@import 'tailwindcss' source("../app");
118+
@tailwind utilities source("../app");
119+
`,
120+
expected: [],
121+
})
122+
123+
runTest('source("…") must not be a glob', {
124+
language: 'css',
125+
code: `
126+
@import 'tailwindcss' source('../app/**/*.html');
127+
@import 'tailwindcss' source('../app/index.{html,js}');
128+
@tailwind utilities source('../app/**/*.html');
129+
@tailwind utilities source('../app/index.{html,js}');
130+
`,
131+
expected: [
132+
{
133+
code: 'invalidSourceDirective',
134+
message: `source('../app/**/*.html') uses a glob but a glob cannot be used here. Use a directory name instead.`,
135+
range: {
136+
start: { line: 1, character: 35 },
137+
end: { line: 1, character: 53 },
138+
},
139+
},
140+
{
141+
code: 'invalidSourceDirective',
142+
message: `source('../app/index.{html,js}') uses a glob but a glob cannot be used here. Use a directory name instead.`,
143+
range: {
144+
start: { line: 2, character: 35 },
145+
end: { line: 2, character: 59 },
146+
},
147+
},
148+
{
149+
code: 'invalidSourceDirective',
150+
message: `source('../app/**/*.html') uses a glob but a glob cannot be used here. Use a directory name instead.`,
151+
range: {
152+
start: { line: 3, character: 33 },
153+
end: { line: 3, character: 51 },
154+
},
155+
},
156+
{
157+
code: 'invalidSourceDirective',
158+
message: `source('../app/index.{html,js}') uses a glob but a glob cannot be used here. Use a directory name instead.`,
159+
range: {
160+
start: { line: 4, character: 33 },
161+
end: { line: 4, character: 57 },
162+
},
163+
},
164+
],
165+
})
166+
167+
runTest('paths given to source("…") must error when not POSIX', {
168+
language: 'css',
169+
code: String.raw`
170+
@import 'tailwindcss' source('C:\\absolute\\path');
171+
@import 'tailwindcss' source('C:relative.txt');
172+
`,
173+
expected: [
174+
{
175+
code: 'invalidSourceDirective',
176+
message:
177+
'POSIX-style paths are required with source() but `C:\\absolute\\path` is a Windows-style path.',
178+
range: {
179+
start: { line: 1, character: 35 },
180+
end: { line: 1, character: 55 },
181+
},
182+
},
183+
{
184+
code: 'invalidSourceDirective',
185+
message:
186+
'POSIX-style paths are required with source() but `C:relative.txt` is a Windows-style path.',
187+
range: {
188+
start: { line: 2, character: 35 },
189+
end: { line: 2, character: 51 },
190+
},
191+
},
192+
],
193+
})
194+
})

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

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { getInvalidVariantDiagnostics } from './getInvalidVariantDiagnostics'
88
import { getInvalidConfigPathDiagnostics } from './getInvalidConfigPathDiagnostics'
99
import { getInvalidTailwindDirectiveDiagnostics } from './getInvalidTailwindDirectiveDiagnostics'
1010
import { getRecommendedVariantOrderDiagnostics } from './getRecommendedVariantOrderDiagnostics'
11+
import { getInvalidSourceDiagnostics } from './getInvalidSourceDiagnostics'
1112

1213
export async function doValidate(
1314
state: State,
@@ -19,6 +20,7 @@ export async function doValidate(
1920
DiagnosticKind.InvalidVariant,
2021
DiagnosticKind.InvalidConfigPath,
2122
DiagnosticKind.InvalidTailwindDirective,
23+
DiagnosticKind.InvalidSourceDirective,
2224
DiagnosticKind.RecommendedVariantOrder,
2325
],
2426
): Promise<AugmentedDiagnostic[]> {
@@ -44,6 +46,9 @@ export async function doValidate(
4446
...(only.includes(DiagnosticKind.InvalidTailwindDirective)
4547
? getInvalidTailwindDirectiveDiagnostics(state, document, settings)
4648
: []),
49+
...(only.includes(DiagnosticKind.InvalidSourceDirective)
50+
? getInvalidSourceDiagnostics(state, document, settings)
51+
: []),
4752
...(only.includes(DiagnosticKind.RecommendedVariantOrder)
4853
? await getRecommendedVariantOrderDiagnostics(state, document, settings)
4954
: []),

0 commit comments

Comments
 (0)