From 28b4abb64407ea77558a11056529c54a7ed9c38a Mon Sep 17 00:00:00 2001 From: Brad Cornes Date: Mon, 20 Mar 2023 11:12:02 +0000 Subject: [PATCH] Support TS/ESM config files (#738) --- package-lock.json | 285 ++++++++++++++++-- .../tailwindcss-language-server/package.json | 2 +- .../src/lib/constants.ts | 3 +- .../tailwindcss-language-server/src/server.ts | 161 +++++----- .../src/util/getModuleDependencies.ts | 58 ++-- .../src/util/state.ts | 1 + 6 files changed, 386 insertions(+), 124 deletions(-) diff --git a/package-lock.json b/package-lock.json index fd9649c..b4d68db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "debounce": "1.2.0", "deepmerge": "4.2.2", "detect-indent": "6.0.0", - "detective": "5.2.0", + "detective-typescript": "9.0.0", "dlv": "1.1.3", "dset": "3.1.2", "enhanced-resolve-301": "0.0.1", @@ -4964,6 +4964,18 @@ } } }, + "node_modules/@typescript-eslint/types": { + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/typescript-estree": { "version": "2.34.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", @@ -4990,6 +5002,30 @@ } } }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", + "dependencies": { + "@typescript-eslint/types": "5.55.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@zkochan/cmd-shim": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@zkochan/cmd-shim/-/cmd-shim-3.1.0.tgz", @@ -5424,6 +5460,14 @@ "node": ">=0.10.0" } }, + "node_modules/ast-module-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-3.0.0.tgz", + "integrity": "sha512-CMxMCOCS+4D+DkOQfuZf+vLrSEmY/7xtORwdxs4wtcC1wVgvk2MqFFTwQCFhvWsI4KPU9lcWXPI8DgRiz+xetQ==", + "engines": { + "node": ">=6.0" + } + }, "node_modules/ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -7716,20 +7760,113 @@ "node": ">=8" } }, - "node_modules/detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "node_modules/detective-typescript": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-9.0.0.tgz", + "integrity": "sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==", "dependencies": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - }, - "bin": { - "detective": "bin/detective.js" + "@typescript-eslint/typescript-estree": "^5.13.0", + "ast-module-types": "^3.0.0", + "node-source-walk": "^5.0.0", + "typescript": "^4.5.5" }, "engines": { - "node": ">=0.8.0" + "node": "^12.20.0 || ^14.14.0 || >=16.0.0" + } + }, + "node_modules/detective-typescript/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", + "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", + "dependencies": { + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/detective-typescript/node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/detective-typescript/node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/detective-typescript/node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/detective-typescript/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detective-typescript/node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/detective-typescript/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" } }, "node_modules/dezalgo": { @@ -15416,6 +15553,17 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" }, + "node_modules/node-source-walk": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", + "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", + "dependencies": { + "@babel/parser": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", @@ -25580,6 +25728,11 @@ "eslint-visitor-keys": "^1.1.0" } }, + "@typescript-eslint/types": { + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz", + "integrity": "sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==" + }, "@typescript-eslint/typescript-estree": { "version": "2.34.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", @@ -25594,6 +25747,22 @@ "tsutils": "^3.17.1" } }, + "@typescript-eslint/visitor-keys": { + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz", + "integrity": "sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==", + "requires": { + "@typescript-eslint/types": "5.55.0", + "eslint-visitor-keys": "^3.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" + } + } + }, "@zkochan/cmd-shim": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@zkochan/cmd-shim/-/cmd-shim-3.1.0.tgz", @@ -25927,6 +26096,11 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, + "ast-module-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-3.0.0.tgz", + "integrity": "sha512-CMxMCOCS+4D+DkOQfuZf+vLrSEmY/7xtORwdxs4wtcC1wVgvk2MqFFTwQCFhvWsI4KPU9lcWXPI8DgRiz+xetQ==" + }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -27696,14 +27870,79 @@ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==" }, - "detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "detective-typescript": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-9.0.0.tgz", + "integrity": "sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==", "requires": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" + "@typescript-eslint/typescript-estree": "^5.13.0", + "ast-module-types": "^3.0.0", + "node-source-walk": "^5.0.0", + "typescript": "^4.5.5" + }, + "dependencies": { + "@typescript-eslint/typescript-estree": { + "version": "5.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz", + "integrity": "sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==", + "requires": { + "@typescript-eslint/types": "5.55.0", + "@typescript-eslint/visitor-keys": "5.55.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + } } }, "dezalgo": { @@ -33690,6 +33929,14 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" }, + "node-source-walk": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", + "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", + "requires": { + "@babel/parser": "^7.0.0" + } + }, "nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", diff --git a/packages/tailwindcss-language-server/package.json b/packages/tailwindcss-language-server/package.json index 395af48..f32d1b2 100644 --- a/packages/tailwindcss-language-server/package.json +++ b/packages/tailwindcss-language-server/package.json @@ -46,7 +46,7 @@ "culori": "0.20.1", "debounce": "1.2.0", "deepmerge": "4.2.2", - "detective": "5.2.0", + "detective-typescript": "9.0.0", "dlv": "1.1.3", "dset": "3.1.2", "enhanced-resolve-301": "0.0.1", diff --git a/packages/tailwindcss-language-server/src/lib/constants.ts b/packages/tailwindcss-language-server/src/lib/constants.ts index 7324327..4f9462c 100644 --- a/packages/tailwindcss-language-server/src/lib/constants.ts +++ b/packages/tailwindcss-language-server/src/lib/constants.ts @@ -1,3 +1,4 @@ -export const CONFIG_GLOB = '{tailwind,tailwind.config,tailwind.*.config,tailwind.config.*}.{js,cjs}' +export const CONFIG_GLOB = + '{tailwind,tailwind.config,tailwind.*.config,tailwind.config.*}.{js,cjs,ts,mjs}' export const PACKAGE_LOCK_GLOB = '{package-lock.json,yarn.lock,pnpm-lock.yaml}' export const CSS_GLOB = '*.{css,scss,sass,less,pcss}' diff --git a/packages/tailwindcss-language-server/src/server.ts b/packages/tailwindcss-language-server/src/server.ts index 54cb88c..b519194 100644 --- a/packages/tailwindcss-language-server/src/server.ts +++ b/packages/tailwindcss-language-server/src/server.ts @@ -608,6 +608,7 @@ async function createProjectService( let pluginVersions: string | undefined let browserslist: string[] | undefined let resolveConfigFn: (config: any) => any + let loadConfigFn: (path: string) => any let featureFlags: FeatureFlags = { future: [], experimental: [] } let applyComplexClasses: any @@ -675,6 +676,10 @@ async function createProjectService( } } + try { + loadConfigFn = require(resolveFrom(tailwindDir, './loadConfig.js')) + } catch {} + if (semver.gte(tailwindcssVersion, '1.4.0') && semver.lte(tailwindcssVersion, '1.99.0')) { const browserslistPath = resolveFrom(tailwindDir, 'browserslist') // TODO: set path to nearest dir with package.json? @@ -810,6 +815,7 @@ async function createProjectService( postcss: { version: postcssVersion, module: postcss }, postcssSelectorParser: { module: postcssSelectorParser }, resolveConfig: { module: resolveConfigFn }, + loadConfig: { module: loadConfigFn }, jit: jitModules, } state.browserslist = browserslist @@ -893,7 +899,7 @@ async function createProjectService( clearRequireCache() - const { tailwindcss, postcss, resolveConfig } = state.modules + const { tailwindcss, postcss, resolveConfig, loadConfig } = state.modules const sepLocation = semver.gte(tailwindcss.version, '0.99.0') ? ['separator'] : ['options', 'separator'] @@ -901,85 +907,91 @@ async function createProjectService( let originalConfig: any let isV3 = semver.gte(tailwindcss.version, '2.99.0') + let hook: Hook - let hook = new Hook(fs.realpathSync(state.configPath), (exports) => { - originalConfig = klona(exports) + if (loadConfig.module) { + originalConfig = await loadConfig.module(state.configPath) + state.jit = true + } else { + hook = new Hook(fs.realpathSync(state.configPath), (exports) => { + originalConfig = klona(exports) - let separator = dlv(exports, sepLocation) - if (typeof separator !== 'string') { - separator = ':' - } - dset(exports, sepLocation, `__TWSEP__${separator}__TWSEP__`) - exports[isV3 ? 'content' : 'purge'] = [] - - let mode = getMode(exports) - deleteMode(exports) - - let isJit = isV3 || (state.modules.jit && mode === 'jit') - - if (isJit) { - state.jit = true - exports.variants = [] - - if (Array.isArray(exports.presets)) { - for (let preset of exports.presets) { - presetVariants.push(preset.variants) - preset.variants = [] - } + let separator = dlv(exports, sepLocation) + if (typeof separator !== 'string') { + separator = ':' } - } else { - state.jit = false - } + dset(exports, sepLocation, `__TWSEP__${separator}__TWSEP__`) + exports[isV3 ? 'content' : 'purge'] = [] - if (state.corePlugins) { - let corePluginsConfig = {} - for (let pluginName of state.corePlugins) { - corePluginsConfig[pluginName] = true - } - exports.corePlugins = corePluginsConfig - } + let mode = getMode(exports) + deleteMode(exports) - // inject JIT `matchUtilities` function - if (Array.isArray(exports.plugins)) { - exports.plugins = exports.plugins.map((plugin) => { - if (plugin.__isOptionsFunction) { - plugin = plugin() - } - if (typeof plugin === 'function') { - let newPlugin = (...args) => { - if (!args[0].matchUtilities) { - args[0].matchUtilities = () => {} - } - return plugin(...args) + let isJit = isV3 || (state.modules.jit && mode === 'jit') + + if (isJit) { + state.jit = true + exports.variants = [] + + if (Array.isArray(exports.presets)) { + for (let preset of exports.presets) { + presetVariants.push(preset.variants) + preset.variants = [] } - // @ts-ignore - newPlugin.__intellisense_cache_bust = Math.random() - return newPlugin } - if (plugin.handler) { - return { - ...plugin, - handler: (...args) => { + } else { + state.jit = false + } + + if (state.corePlugins) { + let corePluginsConfig = {} + for (let pluginName of state.corePlugins) { + corePluginsConfig[pluginName] = true + } + exports.corePlugins = corePluginsConfig + } + + // inject JIT `matchUtilities` function + if (Array.isArray(exports.plugins)) { + exports.plugins = exports.plugins.map((plugin) => { + if (plugin.__isOptionsFunction) { + plugin = plugin() + } + if (typeof plugin === 'function') { + let newPlugin = (...args) => { if (!args[0].matchUtilities) { args[0].matchUtilities = () => {} } - return plugin.handler(...args) - }, - __intellisense_cache_bust: Math.random(), + return plugin(...args) + } + // @ts-ignore + newPlugin.__intellisense_cache_bust = Math.random() + return newPlugin } - } - return plugin - }) + if (plugin.handler) { + return { + ...plugin, + handler: (...args) => { + if (!args[0].matchUtilities) { + args[0].matchUtilities = () => {} + } + return plugin.handler(...args) + }, + __intellisense_cache_bust: Math.random(), + } + } + return plugin + }) + } + + return exports + }) + + try { + require(state.configPath) + } catch (error) { + hook.unhook() + throw error } - - return exports - }) - - try { - require(state.configPath) - } catch (error) { - hook.unhook() - throw error } if (!originalConfig) { @@ -1029,14 +1041,14 @@ async function createProjectService( delete state.classList } } catch (error) { - hook.unhook() + hook?.unhook() throw error } let postcssResult: Result if (state.classList) { - hook.unhook() + hook?.unhook() } else { try { postcssResult = await postcss @@ -1060,7 +1072,7 @@ async function createProjectService( } catch (error) { throw error } finally { - hook.unhook() + hook?.unhook() } } @@ -1703,6 +1715,13 @@ class TW { continue } + if ( + (configPath.endsWith('.ts') || configPath.endsWith('.mjs')) && + !semver.gte(twVersion, '3.3.0') + ) { + continue + } + configTailwindVersionMap.set(configPath, twVersion) let contentSelector: Array = [] diff --git a/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts b/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts index 84de7f8..15f45d0 100644 --- a/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts +++ b/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts @@ -1,47 +1,41 @@ import fs from 'fs' import path from 'path' import resolve from 'resolve' -import detective from 'detective' +import detective from 'detective-typescript' import normalizePath from 'normalize-path' -export function getModuleDependencies(modulePath: string): string[] { - return _getModuleDependencies(modulePath) - .map(({ file }) => file) - .filter((file) => file !== modulePath) - .map((file) => normalizePath(file)) +function createModule(file: string): { file: string; requires: string[] } { + let source = fs.readFileSync(file, 'utf-8') + return { file, requires: detective(source, { mixedImports: true }) } } -function createModule(file) { - const source = fs.readFileSync(file, 'utf-8') - const requires = detective(source) +function* _getModuleDependencies(entryFile: string): Generator { + yield entryFile - return { file, requires } -} + let mod = createModule(entryFile) -function _getModuleDependencies(entryFile) { - const rootModule = createModule(entryFile) - const modules = [rootModule] + let ext = path.extname(entryFile) + let isTypeScript = ext === '.ts' || ext === '.cts' || ext === '.mts' + let extensions = [...(isTypeScript ? ['.ts', '.cts', '.mts'] : []), '.js', '.cjs', '.mjs'] // Iterate over the modules, even when new // ones are being added - for (const mdl of modules) { - mdl.requires - .filter((dep) => { - // Only track local modules, not node_modules - return dep.startsWith('./') || dep.startsWith('../') - }) - .forEach((dep) => { - try { - const basedir = path.dirname(mdl.file) - const depPath = resolve.sync(dep, { basedir }) - const depModule = createModule(depPath) + for (let dep of mod.requires) { + // Only track local modules, not node_modules + if (!dep.startsWith('./') && !dep.startsWith('../')) { + continue + } - modules.push(depModule) - } catch (_err) { - // eslint-disable-next-line no-empty - } - }) + try { + let basedir = path.dirname(mod.file) + let depPath = resolve.sync(dep, { basedir, extensions }) + yield* _getModuleDependencies(depPath) + } catch {} } - - return modules +} + +export function getModuleDependencies(entryFile: string): string[] { + return Array.from(_getModuleDependencies(entryFile)) + .filter((file) => file !== entryFile) + .map((file) => normalizePath(file)) } diff --git a/packages/tailwindcss-language-service/src/util/state.ts b/packages/tailwindcss-language-service/src/util/state.ts index 51677af..681ae5f 100644 --- a/packages/tailwindcss-language-service/src/util/state.ts +++ b/packages/tailwindcss-language-service/src/util/state.ts @@ -105,6 +105,7 @@ export interface State { postcss?: { version: string; module: Postcss } postcssSelectorParser?: { module: any } resolveConfig?: { module: any } + loadConfig?: { module: any } jit?: { generateRules: { module: any } createContext: { module: any }