diff --git a/.eslintrc b/.eslintrc index 6d16bff..90b5a17 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,5 +1,8 @@ { "root": true, + "parserOptions": { + "ecmaVersion": "latest" + }, "extends": [ "plugin:prettier/recommended", "plugin:mdx/recommended" diff --git a/package.json b/package.json index a9d0e6b..e95c0ef 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/index.ts b/src/index.ts index 9e820af..f1beb00 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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' @@ -26,22 +20,9 @@ const globSync = createSyncFn( 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 @@ -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 { @@ -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, }) @@ -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 @@ -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, }) @@ -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) @@ -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 -) => (...matchArgs: Parameters) => - | { - 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 @@ -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`. */ diff --git a/tests/baseEslintConfig.js b/tests/baseEslintConfig.js index 45a8257..13ded1f 100644 --- a/tests/baseEslintConfig.js +++ b/tests/baseEslintConfig.js @@ -1,3 +1,6 @@ +/** + * @param {string} project + */ module.exports = project => ({ parser: '@typescript-eslint/parser', extends: [ diff --git a/yarn.lock b/yarn.lock index a6af4b6..0346a6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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" @@ -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"