Skip to content

Commit

Permalink
feat!: use get-tsconfig to replace tsconfig-paths
Browse files Browse the repository at this point in the history
  • Loading branch information
JounQin committed Jun 25, 2022
1 parent 322cb29 commit 78a08e0
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 129 deletions.
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"root": true,
"parserOptions": {
"ecmaVersion": "latest"
},
"extends": [
"plugin:prettier/recommended",
"plugin:mdx/recommended"
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@
},
"dependencies": {
"debug": "^4.3.4",
"get-tsconfig": "^4.0.6",
"globby": "^13.1.2",
"is-glob": "^4.0.3",
"resolve": "^1.22.1",
"synckit": "^0.7.1",
"tsconfig-paths": "^4.0.0"
"synckit": "^0.7.1"
},
"devDependencies": {
"@1stg/lib-config": "^6.2.3",
Expand Down
140 changes: 22 additions & 118 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@ import path from 'node:path'
import { fileURLToPath } from 'node:url'

import debug from 'debug'
import { createPathsMatcher, getTsconfig } from 'get-tsconfig'
import isGlob from 'is-glob'
import * as _resolve from 'resolve'
import { isCore, type PackageJSON, sync, SyncOpts } from 'resolve'
import { createSyncFn } from 'synckit'
import {
ConfigLoaderSuccessResult,
createMatchPath,
loadConfig,
ConfigLoaderResult,
MatchPath,
} from 'tsconfig-paths'

const IMPORTER_NAME = 'eslint-import-resolver-typescript'

Expand All @@ -26,22 +20,9 @@ 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',
]

export const interfaceVersion = 2

export type TsResolverOptions = _resolve.SyncOpts & {
export type TsResolverOptions = SyncOpts & {
alwaysTryTypes?: boolean
/**
* @deprecated use `project` instead
Expand Down Expand Up @@ -72,7 +53,7 @@ export function resolve(
source = removeQuerystring(source)

// don't worry about core node modules
if (_resolve.isCore(source)) {
if (isCore(source)) {
log('matched core:', source)

return {
Expand All @@ -84,16 +65,14 @@ export function resolve(
initMappers(options)
const mappedPath = getMappedPath(source)
if (mappedPath) {
log('matched ts path:', mappedPath.path)
log('matched ts path:', mappedPath)
}

// 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?.path ?? source, {
foundNodePath = tsResolve(mappedPath ?? source, {
...options,
extensions:
mappedPath?.extensions ?? options.extensions ?? defaultExtensions,
basedir: path.dirname(path.resolve(file)),
packageFilter: options.packageFilter ?? packageFilterDefault,
})
Expand Down Expand Up @@ -136,7 +115,7 @@ export function resolve(
}
}

function packageFilterDefault(pkg: _resolve.PackageJSON) {
function packageFilterDefault(pkg: PackageJSON) {
pkg.main =
pkg.types || pkg.typings || pkg.module || pkg['jsnext:main'] || pkg.main
return pkg
Expand Down Expand Up @@ -172,13 +151,13 @@ 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: _resolve.SyncOpts): string {
function tsResolve(id: string, opts: SyncOpts): string {
try {
return _resolve.sync(id, opts)
return sync(id, opts)
} catch (error) {
const resolved = resolveExtension(id)
if (resolved) {
return _resolve.sync(resolved.path, {
return sync(resolved.path, {
...opts,
extensions: resolved.extensions ?? opts.extensions,
})
Expand All @@ -202,24 +181,20 @@ function removeJsExtension(id: string) {
}

let mappersBuildForOptions: TsResolverOptions
let mappers:
| Array<
(source: string) =>
| {
path: string
extensions?: string[]
}
| undefined
>
| undefined
let mappers: Array<((specifier: string) => string[]) | null> | undefined

/**
* @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'
* @returns The mapped path of the module or undefined
*/
function getMappedPath(source: string) {
const paths = mappers!.map(mapper => mapper(source)).filter(path => !!path)
const paths = mappers!
.map(mapper => mapper?.(source))
.filter(path => !!path)
.flat()

console.log('source:', source)
console.log('paths:', paths)

if (paths.length > 1) {
log('found multiple matching ts paths:', paths)
Expand All @@ -228,51 +203,6 @@ function getMappedPath(source: string) {
return paths[0]
}

/**
* Like `createMatchPath` from `tsconfig-paths` package, but considers
* that the module id could have a .mjs, .cjs, .js or .jsx extension.
*
* The default resolved path does not include the extension, so we need to return it for reusing,
* otherwise `.mts`, `.cts`, `.d.mts`, `.d.cts` will not be used by default, see also @link {defaultExtensions}.
*/
const createExtendedMatchPath: (
...createArgs: Parameters<typeof createMatchPath>
) => (...matchArgs: Parameters<MatchPath>) =>
| {
path: string
extensions?: string[]
}
| undefined = (...createArgs) => {
const matchPath = createMatchPath(...createArgs)

return (id, readJson, fileExists, extensions) => {
const match = matchPath(id, readJson, fileExists, extensions)

if (match != null) {
return {
path: match,
}
}

const resolved = resolveExtension(id)

if (resolved) {
const match = matchPath(
resolved.path,
readJson,
fileExists,
resolved.extensions ?? extensions,
)
if (match) {
return {
path: match,
extensions: resolved.extensions,
}
}
}
}
}

function initMappers(options: TsResolverOptions) {
if (mappers && mappersBuildForOptions === options) {
return
Expand Down Expand Up @@ -307,40 +237,14 @@ function initMappers(options: TsResolverOptions) {
]),
]

mappers = projectPaths
.map(loadConfig)
.filter(isConfigLoaderSuccessResult)
.map(configLoaderResult => {
const matchPath = createExtendedMatchPath(
configLoaderResult.absoluteBaseUrl,
configLoaderResult.paths,
)

return (source: string) =>
// look for files based on setup tsconfig "paths"
matchPath(
source,
undefined,
undefined,
options.extensions ?? defaultExtensions,
)
})
mappers = projectPaths.map(projectPath => {
const tsconfigResult = getTsconfig(projectPath)
return tsconfigResult && createPathsMatcher(tsconfigResult)
})

mappersBuildForOptions = options
}

function isConfigLoaderSuccessResult(
configLoaderResult: ConfigLoaderResult,
): configLoaderResult is ConfigLoaderSuccessResult {
if (configLoaderResult.resultType !== 'success') {
// this can happen if the user has problems with their tsconfig
// or if it's valid, but they don't have baseUrl set
log('failed to init tsconfig-paths:', configLoaderResult.message)
return false
}
return true
}

/**
* For a scoped package, we must look in `@types/foo__bar` instead of `@types/@foo/bar`.
*/
Expand Down
3 changes: 3 additions & 0 deletions tests/baseEslintConfig.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* @param {string} project
*/
module.exports = project => ({
parser: '@typescript-eslint/parser',
extends: [
Expand Down
14 changes: 5 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5169,6 +5169,11 @@ get-symbol-description@^1.0.0:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"

get-tsconfig@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.0.6.tgz#31ee086022b1261fccf89cfc7460db0f3c02fa57"
integrity sha512-yK9g+lk9PSaYS4RM9jnlmFSyymNDdLaIk42h6uOO6DOvqKEpL4KhUAcI1/7/sWe8+FWZe1/EjFXFfvv6T+cgPA==

git-raw-commits@^2.0.0, git-raw-commits@^2.0.8:
version "2.0.11"
resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.11.tgz#bc3576638071d18655e1cc60d7f524920008d723"
Expand Down Expand Up @@ -10263,15 +10268,6 @@ tsconfig-paths@^3.14.1:
minimist "^1.2.6"
strip-bom "^3.0.0"

tsconfig-paths@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.0.0.tgz#1082f5d99fd127b72397eef4809e4dd06d229b64"
integrity sha512-SLBg2GBKlR6bVtMgJJlud/o3waplKtL7skmLkExomIiaAtLGtVsoXIqP3SYdjbcH9lq/KVv7pMZeCBpLYOit6Q==
dependencies:
json5 "^2.2.1"
minimist "^1.2.6"
strip-bom "^3.0.0"

"tslib@1 || 2", tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
Expand Down

0 comments on commit 78a08e0

Please sign in to comment.