diff --git a/package-lock.json b/package-lock.json
index b4d68dbff3fa151c9897a1b6fb0a50f3e3b253a3..e1867a2c61983232552b9c0ad32994fb874ed952 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,7 +29,6 @@ "culori": "0.20.1",
"debounce": "1.2.0",
"deepmerge": "4.2.2",
"detect-indent": "6.0.0",
- "detective-typescript": "9.0.0",
"dlv": "1.1.3",
"dset": "3.1.2",
"enhanced-resolve-301": "0.0.1",
@@ -4964,18 +4963,6 @@ "optional": true
}
}
},
- "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",
@@ -5000,30 +4987,6 @@ "peerDependenciesMeta": {
"typescript": {
"optional": true
}
- }
- },
- "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": {
@@ -5458,14 +5421,6 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
"engines": {
"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": {
@@ -7760,115 +7715,6 @@ "engines": {
"node": ">=8"
}
},
- "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": {
- "@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": "^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": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
@@ -15552,17 +15398,6 @@ "node_modules/node-releases": {
"version": "2.0.10",
"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",
@@ -25728,11 +25563,6 @@ "@typescript-eslint/typescript-estree": "2.34.0",
"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",
@@ -25745,22 +25575,6 @@ "is-glob": "^4.0.1",
"lodash": "^4.17.15",
"semver": "^7.3.2",
"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": {
@@ -26095,11 +25909,6 @@ "assign-symbols": {
"version": "1.0.0",
"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",
@@ -27870,81 +27679,6 @@ "version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
"integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="
},
- "detective-typescript": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-9.0.0.tgz",
- "integrity": "sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==",
- "requires": {
- "@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": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
@@ -33928,14 +33662,6 @@ "node-releases": {
"version": "2.0.10",
"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",
diff --git a/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts b/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts
index 15f45d0a5a53ce5c3c0eb00f67d80d83be4d0d2e..fc0ae8cfa993e6c178fbec633698627d591b82e5 100644
--- a/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts
+++ b/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts
@@ -1,41 +1,87 @@
+// https://github.com/tailwindlabs/tailwindcss/blob/e046a37dbc17f163b066cd34a559e7c8a276bd8b/src/lib/getModuleDependencies.js
import fs from 'fs'
import path from 'path'
-import resolve from 'resolve'
-import detective from 'detective-typescript'
import normalizePath from 'normalize-path'
-function createModule(file: string): { file: string; requires: string[] } {
- let source = fs.readFileSync(file, 'utf-8')
- return { file, requires: detective(source, { mixedImports: true }) }
-}
+let jsExtensions = ['.js', '.cjs', '.mjs']
-function* _getModuleDependencies(entryFile: string): Generator<string> {
- yield entryFile
+// Given the current file `a.ts`, we want to make sure that when importing `b` that we resolve
+// `b.ts` before `b.js`
+//
+// E.g.:
+//
+// a.ts
+// b // .ts
+// c // .ts
+// a.js
+// b // .js or .ts
- let mod = createModule(entryFile)
+let jsResolutionOrder = ['', '.js', '.cjs', '.mjs', '.ts', '.cts', '.mts', '.jsx', '.tsx']
+let tsResolutionOrder = ['', '.ts', '.cts', '.mts', '.tsx', '.js', '.cjs', '.mjs', '.jsx']
- let ext = path.extname(entryFile)
- let isTypeScript = ext === '.ts' || ext === '.cts' || ext === '.mts'
- let extensions = [...(isTypeScript ? ['.ts', '.cts', '.mts'] : []), '.js', '.cjs', '.mjs']
+function resolveWithExtension(file: string, extensions: string[]): string | null {
+ // Try to find `./a.ts`, `./a.ts`, ... from `./a`
+ for (let ext of extensions) {
+ let full = `${file}${ext}`
+ if (fs.existsSync(full) && fs.statSync(full).isFile()) {
+ return full
+ }
+ }
- // Iterate over the modules, even when new
- // ones are being added
- for (let dep of mod.requires) {
- // Only track local modules, not node_modules
- if (!dep.startsWith('./') && !dep.startsWith('../')) {
- continue
+ // Try to find `./a/index.js` from `./a`
+ for (let ext of extensions) {
+ let full = `${file}/index${ext}`
+ if (fs.existsSync(full)) {
+ return full
}
+ }
- try {
- let basedir = path.dirname(mod.file)
- let depPath = resolve.sync(dep, { basedir, extensions })
- yield* _getModuleDependencies(depPath)
- } catch {}
+ return null
+}
+
+function* _getModuleDependencies(
+ filename: string,
+ base: string,
+ seen: Set<string>
+): Generator<string> {
+ let ext = path.extname(filename)
+
+ // Try to find the file
+ let absoluteFile = resolveWithExtension(
+ path.resolve(base, filename),
+ jsExtensions.includes(ext) ? jsResolutionOrder : tsResolutionOrder
+ )
+ if (absoluteFile === null) return // File doesn't exist
+
+ // Prevent infinite loops when there are circular dependencies
+ if (seen.has(absoluteFile)) return // Already seen
+ seen.add(absoluteFile)
+
+ // Mark the file as a dependency
+ yield absoluteFile
+
+ // Resolve new base for new imports/requires
+ base = path.dirname(absoluteFile)
+
+ let contents = fs.readFileSync(absoluteFile, 'utf-8')
+
+ // Find imports/requires
+ for (let match of [
+ ...contents.matchAll(/import[\s\S]*?['"](.{3,}?)['"]/gi),
+ ...contents.matchAll(/import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi),
+ ...contents.matchAll(/require\(['"`](.{3,})['"`]\)/gi),
+ ]) {
+ // Bail out if it's not a relative file
+ if (!match[1].startsWith('.')) continue
+
+ yield* _getModuleDependencies(match[1], base, seen)
}
}
-export function getModuleDependencies(entryFile: string): string[] {
- return Array.from(_getModuleDependencies(entryFile))
- .filter((file) => file !== entryFile)
+export function getModuleDependencies(absoluteFilePath: string): string[] {
+ return Array.from(
+ _getModuleDependencies(absoluteFilePath, path.dirname(absoluteFilePath), new Set())
+ )
+ .filter((file) => file !== absoluteFilePath)
.map((file) => normalizePath(file))
}