11import type { DesignSystem } from '@tailwindcss/language-service/src/util/v4'
22
33import postcss from 'postcss'
4+ import * as fs from 'node:fs/promises'
45import * as path from 'node:path'
5- import { resolveCssImports } from '../../css'
6+ import { resolveCssFrom , resolveCssImports } from '../../css'
67import { resolveFrom } from '../resolveFrom'
78import { pathToFileURL } from 'tailwindcss-language-server/src/utils'
89
@@ -25,29 +26,40 @@ export async function isMaybeV4(css: string): Promise<boolean> {
2526 * Create a loader function that can load plugins and config files relative to
2627 * the CSS file that uses them. However, we don't want missing files to prevent
2728 * everything from working so we'll let the error handler decide how to proceed.
28- *
29- * @param {object } param0
30- * @returns
3129 */
3230function createLoader < T > ( {
31+ legacy,
3332 filepath,
3433 onError,
3534} : {
35+ legacy : boolean
3636 filepath : string
37- onError : ( id : string , error : unknown ) => T
37+ onError : ( id : string , error : unknown , resourceType : string ) => T
3838} ) {
39- let baseDir = path . dirname ( filepath )
4039 let cacheKey = `${ + Date . now ( ) } `
4140
42- return async function loadFile ( id : string ) {
41+ async function loadFile ( id : string , base : string , resourceType : string ) {
4342 try {
44- let resolved = resolveFrom ( baseDir , id )
43+ let resolved = resolveFrom ( base , id )
44+
4545 let url = pathToFileURL ( resolved )
4646 url . searchParams . append ( 't' , cacheKey )
4747
4848 return await import ( url . href ) . then ( ( m ) => m . default ?? m )
4949 } catch ( err ) {
50- return onError ( id , err )
50+ return onError ( id , err , resourceType )
51+ }
52+ }
53+
54+ if ( legacy ) {
55+ let baseDir = path . dirname ( filepath )
56+ return ( id : string ) => loadFile ( id , baseDir , 'module' )
57+ }
58+
59+ return async ( id : string , base : string , resourceType : string ) => {
60+ return {
61+ base,
62+ module : await loadFile ( id , base , resourceType ) ,
5163 }
5264 }
5365}
@@ -65,14 +77,53 @@ export async function loadDesignSystem(
6577 return null
6678 }
6779
80+ let supportsImports = false
81+ try {
82+ await tailwindcss . __unstable__loadDesignSystem ( css , {
83+ loadStylesheet : async ( id : string , base : string ) => {
84+ supportsImports = true
85+ return { base, content : '' }
86+ } ,
87+ } )
88+ } catch { }
89+
6890 // Step 2: Use postcss to resolve `@import` rules in the CSS file
69- // TODO: What if someone is actively editing their config and introduces a syntax error?
70- // We don't want to necessarily throw away the knowledge that we have a v4 project.
71- let resolved = await resolveCssImports ( ) . process ( css , { from : filepath } )
91+ if ( ! supportsImports ) {
92+ let resolved = await resolveCssImports ( ) . process ( css , { from : filepath } )
93+ css = resolved . css
94+ }
7295
7396 // Step 3: Take the resolved CSS and pass it to v4's `loadDesignSystem`
74- let design : DesignSystem = await tailwindcss . __unstable__loadDesignSystem ( resolved . css , {
97+ let design : DesignSystem = await tailwindcss . __unstable__loadDesignSystem ( css , {
98+ base : path . dirname ( filepath ) ,
99+
100+ // v4.0.0-alpha.25+
101+ loadModule : createLoader ( {
102+ legacy : false ,
103+ filepath,
104+ onError : ( id , err , resourceType ) => {
105+ console . error ( `Unable to load ${ resourceType } : ${ id } ` , err )
106+
107+ if ( resourceType === 'config' ) {
108+ return { }
109+ } else if ( resourceType === 'plugin' ) {
110+ return ( ) => { }
111+ }
112+ } ,
113+ } ) ,
114+
115+ loadStylesheet : async ( id : string , base : string ) => {
116+ let resolved = resolveCssFrom ( base , id )
117+
118+ return {
119+ base : path . dirname ( resolved ) ,
120+ content : await fs . readFile ( resolved , 'utf-8' ) ,
121+ }
122+ } ,
123+
124+ // v4.0.0-alpha.24 and below
75125 loadPlugin : createLoader ( {
126+ legacy : true ,
76127 filepath,
77128 onError ( id , err ) {
78129 console . error ( `Unable to load plugin: ${ id } ` , err )
@@ -82,6 +133,7 @@ export async function loadDesignSystem(
82133 } ) ,
83134
84135 loadConfig : createLoader ( {
136+ legacy : true ,
85137 filepath,
86138 onError ( id , err ) {
87139 console . error ( `Unable to load config: ${ id } ` , err )
0 commit comments