mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
* replace `detective-typescript` with our own implementation
We are not parsing the code but just trying to pluck out the
dependencies used via `import` and `require`.
* drop `detective-typescript`
* return a `Set` instead of an `Array`
* resolve rebuilds, but log errors in case they occur
This won't be the prettiest if it happens, but at least we are not
swallowing errors which should make bugs be easier to discover.
See previous commit for an example... 😅
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
80 lines
2.1 KiB
JavaScript
80 lines
2.1 KiB
JavaScript
import fs from 'fs'
|
|
import path from 'path'
|
|
|
|
let jsExtensions = ['.js', '.cjs', '.mjs']
|
|
|
|
// 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 jsResolutionOrder = ['', '.js', '.cjs', '.mjs', '.ts', '.cts', '.mts', '.jsx', '.tsx']
|
|
let tsResolutionOrder = ['', '.ts', '.cts', '.mts', '.tsx', '.js', '.cjs', '.mjs', '.jsx']
|
|
|
|
function resolveWithExtension(file, extensions) {
|
|
// 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
|
|
}
|
|
}
|
|
|
|
// Try to find `./a/index.js` from `./a`
|
|
for (let ext of extensions) {
|
|
let full = `${file}/index${ext}`
|
|
if (fs.existsSync(full)) {
|
|
return full
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
function* _getModuleDependencies(filename, base, seen) {
|
|
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 default function getModuleDependencies(absoluteFilePath) {
|
|
return new Set(
|
|
_getModuleDependencies(absoluteFilePath, path.dirname(absoluteFilePath), new Set())
|
|
)
|
|
}
|