Skip to content

Commit

Permalink
feat!: use enhanced-resolve instead
Browse files Browse the repository at this point in the history
close #85, close #107
  • Loading branch information
JounQin committed Jun 25, 2022
1 parent 6683854 commit 39ab8b1
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 271 deletions.
10 changes: 6 additions & 4 deletions package.json
Expand Up @@ -63,19 +63,21 @@
},
"dependencies": {
"debug": "^4.3.4",
"enhanced-resolve": "^5.9.3",
"get-tsconfig": "^4.0.6",
"globby": "^13.1.2",
"is-core-module": "^2.9.0",
"is-glob": "^4.0.3",
"resolve": "^1.22.1",
"synckit": "^0.7.1"
},
"devDependencies": {
"@1stg/lib-config": "^6.2.3",
"@1stg/lib-config": "^6.3.0",
"@mozilla/glean": "^1.0.0",
"@types/debug": "^4.1.7",
"@types/glob": "^7.2.0",
"@types/enhanced-resolve": "^3.0.7",
"@types/is-core-module": "^2.2.0",
"@types/is-glob": "^4.0.2",
"@types/node": "^18.0.0",
"@types/resolve": "^1.20.2",
"@types/unist": "^2.0.6",
"dummy.js": "link:dummy.js",
"eslint-import-resolver-typescript": "link:.",
Expand Down
82 changes: 56 additions & 26 deletions src/index.ts
Expand Up @@ -3,9 +3,15 @@ import path from 'node:path'
import { fileURLToPath } from 'node:url'

import debug from 'debug'
import {
FileSystem,
ResolveOptions,
Resolver,
ResolverFactory,
} from 'enhanced-resolve'
import { createPathsMatcher, getTsconfig } from 'get-tsconfig'
import isCore from 'is-core-module'
import isGlob from 'is-glob'
import { isCore, type PackageJSON, sync, SyncOpts } from 'resolve'
import { createSyncFn } from 'synckit'

const IMPORTER_NAME = 'eslint-import-resolver-typescript'
Expand All @@ -21,15 +27,37 @@ const globSync = createSyncFn<typeof import('globby').globby>(
path.resolve(_dirname, 'worker.mjs'),
)

/**
* .mts, .cts, .d.mts, .d.cts, .mjs, .cjs are not included because .cjs and .mjs must be used explicitly.
*/
const defaultExtensions = [
'.ts',
'.tsx',
'.d.ts',
'.js',
'.jsx',
'.json',
'.node',
]

const defaultMainFields = ['types', 'typings', 'module', 'jsnext:main', 'main']

export const interfaceVersion = 2

export type TsResolverOptions = SyncOpts & {
export interface TsResolverOptions
extends Omit<ResolveOptions, 'fileSystem' | 'useSyncFileSystemCalls'> {
alwaysTryTypes?: boolean
project?: string[] | string
extensions?: string[]
packageFilter?: (pkg: Record<string, string>) => Record<string, string>
}

const fileSystem = fs as FileSystem

let mappersBuildForOptions: TsResolverOptions
let mappers: Array<((specifier: string) => string[]) | null> | undefined
let resolver: Resolver

/**
* @param {string} source the module to resolve; i.e './some-module'
* @param {string} file the importing file's full path; i.e. '/usr/local/bin/file.js'
Expand All @@ -38,12 +66,20 @@ export type TsResolverOptions = SyncOpts & {
export function resolve(
source: string,
file: string,
options: TsResolverOptions | null,
options?: TsResolverOptions | null,
): {
found: boolean
path?: string | null
} {
options = options ?? {}
const opts: ResolveOptions & TsResolverOptions = {
...options,
extensions: options?.extensions ?? defaultExtensions,
mainFields: options?.mainFields ?? defaultMainFields,
fileSystem,
useSyncFileSystemCalls: true,
}

resolver = ResolverFactory.createResolver(opts)

log('looking for:', source)

Expand All @@ -59,7 +95,7 @@ export function resolve(
}
}

initMappers(options)
initMappers(opts)

const mappedPath = getMappedPath(source, file, true)
if (mappedPath) {
Expand All @@ -69,11 +105,9 @@ export function resolve(
// note that even if we map the path, we still need to do a final resolve
let foundNodePath: string | null | undefined
try {
foundNodePath = tsResolve(mappedPath ?? source, {
...options,
basedir: path.dirname(path.resolve(file)),
packageFilter: options.packageFilter ?? packageFilterDefault,
})
foundNodePath =
tsResolve(mappedPath ?? source, path.dirname(path.resolve(file)), opts) ||
null
} catch {
foundNodePath = null
}
Expand All @@ -82,7 +116,7 @@ export function resolve(
// if path is neither absolute nor relative
if (
(/\.jsx?$/.test(foundNodePath!) ||
(options.alwaysTryTypes && !foundNodePath)) &&
(opts.alwaysTryTypes && !foundNodePath)) &&
!/^@types[/\\]/.test(source) &&
!path.isAbsolute(source) &&
!source.startsWith('.')
Expand Down Expand Up @@ -113,12 +147,6 @@ export function resolve(
}
}

function packageFilterDefault(pkg: PackageJSON) {
pkg.main =
pkg.types || pkg.typings || pkg.module || pkg['jsnext:main'] || pkg.main
return pkg
}

function resolveExtension(id: string) {
const idWithoutJsExt = removeJsExtension(id)

Expand Down Expand Up @@ -149,16 +177,21 @@ function resolveExtension(id: string) {
* Like `sync` from `resolve` package, but considers that the module id
* could have a .js or .jsx extension.
*/
function tsResolve(id: string, opts: SyncOpts): string {
function tsResolve(
source: string,
base: string,
options: ResolveOptions,
): string | false {
try {
return sync(id, opts)
return resolver.resolveSync({}, base, source)
} catch (error) {
const resolved = resolveExtension(id)
const resolved = resolveExtension(source)
if (resolved) {
return sync(resolved.path, {
...opts,
extensions: resolved.extensions ?? opts.extensions,
const resolver = ResolverFactory.createResolver({
...options,
extensions: resolved.extensions ?? options.extensions,
})
return resolver.resolveSync({}, base, resolved.path)
}
throw error
}
Expand All @@ -178,9 +211,6 @@ function removeJsExtension(id: string) {
return id.replace(/\.([cm]js|jsx?)$/, '')
}

let mappersBuildForOptions: TsResolverOptions
let mappers: Array<((specifier: string) => string[]) | null> | undefined

const JS_EXT_PATTERN = /\.([cm]js|jsx?)$/
const RELATIVE_PATH_PATTERN = /^\.{1,2}(\/.*)?$/

Expand Down
3 changes: 2 additions & 1 deletion tests/withJsExtension/test.js
Expand Up @@ -127,4 +127,5 @@ assertResolve(
'../../node_modules/typescript/lib/typescript.js',
)

assertResolve('dummy.js', '../../node_modules/dummy.js/index.js')
// resolves symlinks by default
assertResolve('dummy.js', '../../dummy.js/index.js')
3 changes: 3 additions & 0 deletions tests/withoutPaths/index.ts
Expand Up @@ -15,3 +15,6 @@ import 'json5'

// enable alwaysTryTypes
import 'unist'

// exports
import '@mozilla/glean/webext'

0 comments on commit 39ab8b1

Please sign in to comment.