Skip to content

Commit 99f66e2

Browse files
committed
wip tsconfig support
1 parent 725b746 commit 99f66e2

File tree

19 files changed

+783
-7
lines changed

19 files changed

+783
-7
lines changed

packages/tailwindcss-language-server/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
"rimraf": "3.0.2",
8282
"stack-trace": "0.0.10",
8383
"tailwindcss": "3.4.4",
84+
"tsconfig-paths": "^4.2.0",
8485
"typescript": "5.3.3",
8586
"vite-tsconfig-paths": "^4.3.1",
8687
"vitest": "^1.4.0",

packages/tailwindcss-language-server/src/project-locator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ export class ProjectLocator {
454454
this.resolver ??= await createResolver({
455455
root: process.cwd(),
456456
pnp: true,
457+
tsconfig: true,
457458
})
458459

459460
return this.resolver

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,11 @@ export async function createProjectService(
263263
let resolver!: Resolver
264264

265265
async function getResolver() {
266+
console.log({ getResolver })
266267
resolver ??= await createResolver({
267268
root: projectConfig.folder,
268269
pnp: true,
270+
tsconfig: true,
269271
})
270272

271273
return resolver

packages/tailwindcss-language-server/src/resolver/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as fs from 'node:fs'
22
import * as path from 'node:path'
33
import { CachedInputFileSystem, ResolverFactory, Resolver as BaseResolver } from 'enhanced-resolve'
44
import { loadPnPApi } from './pnp'
5+
import { loadTsConfig } from './tsconfig'
56

67
export interface ResolverOptions {
78
/**
@@ -13,6 +14,11 @@ export interface ResolverOptions {
1314
* Whether or not the resolver should attempt to use PnP resolution
1415
*/
1516
pnp?: boolean
17+
18+
/**
19+
* Whether or not the resolver should load tsconfig path mappings
20+
*/
21+
tsconfig?: boolean
1622
}
1723

1824
export interface Resolver {
@@ -52,6 +58,9 @@ export async function createResolver(opts: ResolverOptions) {
5258
// Load PnP API if requested
5359
let pnpApi = opts.pnp ? await loadPnPApi(opts.root) : null
5460

61+
// Load TSConfig path mappings
62+
let tsconfig = opts.tsconfig ? await loadTsConfig(opts.root) : null
63+
5564
let esmResolver = ResolverFactory.createResolver({
5665
fileSystem,
5766
extensions: ['.mjs', '.js'],
@@ -93,6 +102,11 @@ export async function createResolver(opts: ResolverOptions) {
93102
if (base.startsWith('//')) base = `\\\\${base.slice(2)}`
94103
}
95104

105+
if (tsconfig) {
106+
let match = await tsconfig.resolveId(id, base)
107+
if (match) id = match
108+
}
109+
96110
return new Promise((resolve, reject) => {
97111
resolver.resolve({}, base, id, {}, (err, res) => {
98112
if (err) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as tsconfig from 'tsconfig-paths'
2+
3+
export async function loadTsConfig(root: string) {
4+
// A cached list of tsconfig matchers based on directory
5+
let matchers: Record<string, tsconfig.MatchPath | null> = {}
6+
7+
async function load(base: string) {
8+
if (matchers[base]) return matchers[base]
9+
10+
let config = tsconfig.loadConfig(base)
11+
12+
if (config.resultType === 'failed') {
13+
matchers[base] = null
14+
} else {
15+
matchers[base] = tsconfig.createMatchPath(
16+
config.absoluteBaseUrl,
17+
config.paths,
18+
config.mainFields,
19+
config.addMatchAll,
20+
)
21+
}
22+
23+
return matchers[base]
24+
}
25+
26+
async function resolveId(id: string, base: string) {
27+
let match = await load(base)
28+
29+
return match?.(id)
30+
}
31+
32+
return {
33+
resolveId,
34+
}
35+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@import 'tailwindcss';
2+
3+
@import '#a/file.css';
4+
@import '#b/file.css';
5+
6+
@config '#a/my-config.ts';
7+
@plugin '#a/my-plugin.ts';
8+
9+
@config '#b/my-config.ts';
10+
@plugin '#b/my-plugin.ts';

packages/tailwindcss-language-server/tests/fixtures/v4/path-mappings/package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dependencies": {
3+
"tailwindcss": "^4.0.0-beta.6"
4+
}
5+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@theme {
2+
--color-map-a-css: black;
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type { Config } from 'tailwindcss'
2+
3+
export default {
4+
theme: {
5+
extend: {
6+
colors: {
7+
'map-a-config': 'black',
8+
},
9+
},
10+
},
11+
} satisfies Config
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { PluginAPI } from 'tailwindcss'
2+
import plugin from 'tailwindcss/plugin'
3+
4+
export default plugin(
5+
(api: PluginAPI) => {
6+
//
7+
},
8+
{
9+
theme: {
10+
extend: {
11+
colors: {
12+
'map-a-plugin': 'black',
13+
},
14+
},
15+
},
16+
},
17+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@theme {
2+
--color-map-b-css: black;
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type { Config } from 'tailwindcss'
2+
3+
export default {
4+
theme: {
5+
extend: {
6+
colors: {
7+
'map-b-config': 'black',
8+
},
9+
},
10+
},
11+
} satisfies Config
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { PluginAPI } from 'tailwindcss'
2+
import plugin from 'tailwindcss/plugin'
3+
4+
export default plugin(
5+
(api: PluginAPI) => {
6+
//
7+
},
8+
{
9+
theme: {
10+
extend: {
11+
colors: {
12+
'map-b-plugin': 'black',
13+
},
14+
},
15+
},
16+
},
17+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type { Config } from 'tailwindcss'
2+
3+
export default {
4+
theme: {
5+
extend: {
6+
colors: {
7+
'ts-from-config': 'black',
8+
},
9+
},
10+
},
11+
} satisfies Config
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { PluginAPI } from 'tailwindcss'
2+
import plugin from 'tailwindcss/plugin'
3+
4+
export default plugin(
5+
(api: PluginAPI) => {
6+
//
7+
},
8+
{
9+
theme: {
10+
extend: {
11+
colors: {
12+
'ts-from-plugin': 'black',
13+
},
14+
},
15+
},
16+
},
17+
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"paths": {
4+
"#a/*": ["./src/a"],
5+
"#b/*": ["./src/b"]
6+
}
7+
}
8+
}

packages/tailwindcss-language-server/tests/hover/hover.test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,3 +357,57 @@ withFixture('v4/css-loading-js', (c) => {
357357
},
358358
})
359359
})
360+
361+
withFixture('v4/path-mappings', (c) => {
362+
async function testHover(name, { text, lang, position, expected, expectedRange, settings }) {
363+
test.concurrent.only(name, async ({ expect }) => {
364+
let textDocument = await c.openDocument({ text, lang, settings })
365+
let res = await c.sendRequest('textDocument/hover', {
366+
textDocument,
367+
position,
368+
})
369+
370+
expect(res).toEqual(
371+
expected
372+
? {
373+
contents: {
374+
language: 'css',
375+
value: expected,
376+
},
377+
range: expectedRange,
378+
}
379+
: expected,
380+
)
381+
})
382+
}
383+
384+
testHover('Mapping: CSS Imports', {
385+
text: '<div class="bg-map-a-css">',
386+
position: { line: 0, character: 13 },
387+
expected: '.bg-map-a-css {\n background-color: black;\n}',
388+
expectedRange: {
389+
start: { line: 0, character: 12 },
390+
end: { line: 0, character: 30 },
391+
},
392+
})
393+
394+
testHover('Mapping: Configs', {
395+
text: '<div class="bg-map-a-config">',
396+
position: { line: 0, character: 13 },
397+
expected: '.bg-map-a-config {\n background-color: black;\n}',
398+
expectedRange: {
399+
start: { line: 0, character: 12 },
400+
end: { line: 0, character: 30 },
401+
},
402+
})
403+
404+
testHover('Mapping: Plugins', {
405+
text: '<div class="bg-map-a-plugin">',
406+
position: { line: 0, character: 13 },
407+
expected: '.bg-map-a-plugin {\n background-color: black;\n}',
408+
expectedRange: {
409+
start: { line: 0, character: 12 },
410+
end: { line: 0, character: 30 },
411+
},
412+
})
413+
})

0 commit comments

Comments
 (0)