diff --git a/.eslintrc b/.eslintrc index 19106e5..95a3175 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,7 +4,8 @@ "node": true }, "parserOptions": { - "ecmaVersion": "latest" + "ecmaVersion": "latest", + "sourceType": "module" }, "extends": [ "plugin:prettier/recommended", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f7ed8c..11e2b6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,19 +4,28 @@ on: - push - pull_request +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: default: + name: Lint and Test with Node.js ${{ matrix.node }} on ${{ matrix.os }} strategy: matrix: node: - 16 - 18 - 20 + - 22 os: - ubuntu-latest - windows-latest - macos-latest + fail-fast: false runs-on: ${{ matrix.os }} + env: + YARN_IGNORE_NODE: 1 steps: - uses: actions/checkout@v4 @@ -33,17 +42,12 @@ jobs: with: node-version: ${{ matrix.node }} cache: yarn - env: - YARN_IGNORE_NODE: 1 - name: Install Dependencies run: yarn --immutable - env: - YARN_IGNORE_NODE: 1 - name: Build, Lint and Test run: yarn run-s build lint test typecov env: EFF_NO_LINK_RULES: true PARSER_NO_WATCH: true - YARN_IGNORE_NODE: 1 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 17a1049..925e412 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -4,12 +4,18 @@ on: push: branches: - master + - v3.x pull_request: branches: - master + - v3.x schedule: - cron: '16 11 * * 2' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: analyze: name: Analyze @@ -30,15 +36,15 @@ jobs: uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: '/language:${{ matrix.language }}' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1b54dd0..92ab801 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,11 @@ on: push: branches: - master + - v3.x + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: release: diff --git a/.github/workflows/size-limit.yml b/.github/workflows/size-limit.yml index d09c494..44884f4 100644 --- a/.github/workflows/size-limit.yml +++ b/.github/workflows/size-limit.yml @@ -4,11 +4,16 @@ on: pull_request: branches: - master + - v3.x permissions: contents: read pull-requests: write +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: size-limit: runs-on: ubuntu-latest diff --git a/.nvmrc b/.nvmrc index 1fc5166..9be0c70 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18.20.6 +18.20.7 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dd6496..7031907 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 3.8.4 + +### Patch Changes + +- [#370](https://github.com/import-js/eslint-import-resolver-typescript/pull/370) [`c940785`](https://github.com/import-js/eslint-import-resolver-typescript/commit/c94078504cfb6fd17b775c53d268962a56a2d118) Thanks [@JounQin](https://github.com/JounQin)! - fix: support multiple matching ts paths + ## 3.8.3 ### Patch Changes diff --git a/package.json b/package.json index 758c4c9..c35a251 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-import-resolver-typescript", - "version": "3.8.3", + "version": "3.8.4", "type": "module", "description": "This plugin adds `TypeScript` support to `eslint-plugin-import`", "repository": "git+https://github.com/import-js/eslint-import-resolver-typescript", @@ -54,7 +54,7 @@ "test:dotInclude": "eslint --ext ts,tsx tests/dotInclude --ignore-pattern \"!.dot\"", "test:dotPaths": "eslint --ext ts,tsx tests/dotPaths --ignore-pattern \"!.dot\"", "test:dotProject": "eslint --ext ts,tsx tests/dotProject --ignore-pattern \"!.dot\"", - "test:importXResolverV3": "eslint --config=tests/importXResolverV3/eslint.config.js tests/importXResolverV3", + "test:importXResolverV3": "cross-env ESLINT_USE_FLAT_CONFIG=true eslint --config=tests/importXResolverV3/eslint.config.js tests/importXResolverV3", "test:multipleEslintrcs": "eslint --ext ts,tsx tests/multipleEslintrcs", "test:multipleTsconfigs": "eslint --ext ts,tsx tests/multipleTsconfigs", "test:withJsExtension": "node tests/withJsExtension/test.js && eslint --ext ts,tsx tests/withJsExtension", @@ -90,14 +90,15 @@ "devDependencies": { "@1stg/eslint-config": "7.0.1", "@1stg/lib-config": "^12.0.1", - "@changesets/changelog-github": "^0.5.0", + "@changesets/changelog-github": "^0.5.1", "@changesets/cli": "^2.27.12", "@commitlint/cli": "^17.8.1", "@mozilla/glean": "^3.0.0", "@pkgr/rollup": "^4.1.3", "@types/debug": "^4.1.12", - "@types/node": "^18.19.74", + "@types/node": "^18.19.78", "@types/unist": "^2.0.11", + "cross-env": "^7.0.3", "dummy.js": "link:dummy.js", "eslint": "^8.57.1", "eslint-import-resolver-typescript": "link:.", @@ -111,7 +112,7 @@ "size-limit": "^11.0.0", "size-limit-preset-node-lib": "^0.3.0", "type-coverage": "^2.27.0", - "typescript": "^5.3.2" + "typescript": "~5.1.0" }, "resolutions": { "eslint-import-resolver-typescript": "link:.", diff --git a/src/index.ts b/src/index.ts index bc92c25..1287aef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -181,22 +181,30 @@ export function resolve( initMappers(cachedOptions) - const mappedPath = getMappedPath(source, file, cachedOptions.extensions, true) - if (mappedPath) { - log('matched ts path:', mappedPath) + let mappedPaths = getMappedPaths(source, file, cachedOptions.extensions, true) + + if (mappedPaths.length > 0) { + log('matched ts path:', ...mappedPaths) + } else { + mappedPaths = [source] } // note that even if we map the path, we still need to do a final resolve - let foundNodePath: string | null - try { - foundNodePath = - resolver.resolveSync( + let foundNodePath: string | undefined + for (const mappedPath of mappedPaths) { + try { + const resolved = resolver.resolveSync( {}, path.dirname(path.resolve(file)), - mappedPath ?? source, - ) || null - } catch { - foundNodePath = null + mappedPath, + ) + if (resolved) { + foundNodePath = resolved + break + } + } catch { + log('failed to resolve with', mappedPath) + } } // naive attempt at `@types/*` resolution, @@ -286,16 +294,16 @@ const isModule = (modulePath?: string | undefined): modulePath is string => { * @returns The mapped path of the module or undefined */ // eslint-disable-next-line sonarjs/cognitive-complexity -function getMappedPath( +function getMappedPaths( source: string, file: string, extensions: string[] = defaultExtensions, retry?: boolean, -): string | undefined { +): string[] { const originalExtensions = extensions extensions = ['', ...extensions] - let paths: Array | undefined = [] + let paths: string[] = [] if (RELATIVE_PATH_PATTERN.test(source)) { const resolved = path.resolve(path.dirname(file), source) @@ -341,34 +349,35 @@ function getMappedPath( const tsExt = jsExt.replace('js', 'ts') const basename = source.replace(JS_EXT_PATTERN, '') - const resolved = - getMappedPath(basename + tsExt, file) || - getMappedPath( - basename + '.d' + (tsExt === '.tsx' ? '.ts' : tsExt), - file, - ) + const mappedPaths = getMappedPaths(basename + tsExt, file) - if (resolved) { + const resolved = + mappedPaths.length > 0 + ? mappedPaths + : getMappedPaths( + basename + '.d' + (tsExt === '.tsx' ? '.ts' : tsExt), + file, + ) + + if (resolved.length > 0) { return resolved } } for (const ext of extensions) { + const mappedPaths = isJs ? [] : getMappedPaths(source + ext, file) const resolved = - (isJs ? null : getMappedPath(source + ext, file)) || - getMappedPath(source + `/index${ext}`, file) + mappedPaths.length > 0 + ? mappedPaths + : getMappedPaths(source + `/index${ext}`, file) - if (resolved) { + if (resolved.length > 0) { return resolved } } } - if (paths.length > 1) { - log('found multiple matching ts paths:', paths) - } - - return paths[0] + return paths } // eslint-disable-next-line sonarjs/cognitive-complexity diff --git a/tests/importXResolverV3/eslint.config.js b/tests/importXResolverV3/eslint.config.js index 70a0e56..4fe2fdd 100644 --- a/tests/importXResolverV3/eslint.config.js +++ b/tests/importXResolverV3/eslint.config.js @@ -1,20 +1,31 @@ const path = require('path') -const { createTypeScriptImportResolver } = require('../../lib/index.cjs') +const importX = require('eslint-plugin-import-x') + +const { createTypeScriptImportResolver } = require('../..') const globPattern = './packages/*/tsconfig.json' // in normal cases this is not needed because the __dirname would be the root const absoluteGlobPath = path.join(__dirname, globPattern) -module.exports = { - ...require('eslint-plugin-import-x').flatConfigs.typescript, - settings: { - ...require('eslint-plugin-import-x').flatConfigs.typescript.settings, - 'import-x/resolver-next': [ - createTypeScriptImportResolver({ - project: absoluteGlobPath, - alwaysTryTypes: true, - }), - ], - }, -} +const base = require('../baseEslintConfig.cjs')() + +module.exports = + // don't run on node 16 because lacking of `structuredClone` + +process.versions.node.split('.')[0] <= 16 + ? {} + : { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + import: importX, + }, + settings: { + ...importX.flatConfigs.typescript.settings, + 'import-x/resolver-next': [ + createTypeScriptImportResolver({ + project: absoluteGlobPath, + }), + ], + }, + rules: base.rules, + } diff --git a/yarn.lock b/yarn.lock index 420dcfa..841bba1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2076,14 +2076,14 @@ __metadata: languageName: node linkType: hard -"@changesets/changelog-github@npm:^0.5.0": - version: 0.5.0 - resolution: "@changesets/changelog-github@npm:0.5.0" +"@changesets/changelog-github@npm:^0.5.1": + version: 0.5.1 + resolution: "@changesets/changelog-github@npm:0.5.1" dependencies: "@changesets/get-github-info": "npm:^0.6.0" - "@changesets/types": "npm:^6.0.0" + "@changesets/types": "npm:^6.1.0" dotenv: "npm:^8.1.0" - checksum: a9c01d918f67c3d5dd38a505da29261518bed932c67fe3eb85cc15a485d32c1d11549cd276f121b4e169f26fb20923b435e931e6a5e83e213623dd8c3733cde9 + checksum: 1284e7dc067652edfa14792196e6036849455d121afabe63e8d1a7dc0e8fb0310edb58d1130f2a5944819ae4011eeecc7e0c44c1cda43e6a581a3add187c3447 languageName: node linkType: hard @@ -2268,10 +2268,10 @@ __metadata: languageName: node linkType: hard -"@changesets/types@npm:^6.0.0": - version: 6.0.0 - resolution: "@changesets/types@npm:6.0.0" - checksum: 214c58ff3e3da019c578b94815ec6748729a38b665d950acddf53f3a23073ac7a57dce45812c4bec0cbcd6902c84a482c804457d4c903602005b2399de8a4021 +"@changesets/types@npm:^6.0.0, @changesets/types@npm:^6.1.0": + version: 6.1.0 + resolution: "@changesets/types@npm:6.1.0" + checksum: 2dcd00712cb85d0c53afdd8d0e856b4bf9c0ce8dc36c838c918d44799aacd9ba8659b9ff610ff92b94fc03c8fd2b52c5b05418fcf8a1bd138cd9182414ede373 languageName: node linkType: hard @@ -3724,12 +3724,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.0.0, @types/node@npm:^18.19.74": - version: 18.19.74 - resolution: "@types/node@npm:18.19.74" +"@types/node@npm:^18.0.0, @types/node@npm:^18.19.78": + version: 18.19.78 + resolution: "@types/node@npm:18.19.78" dependencies: undici-types: "npm:~5.26.4" - checksum: 2306bd0b41cdd528b890b210b96f287a5b5035c128f62636057d6616bd612b3f53d32d77f7e76ef41a9f130ea691e6980e6d5942dd625df05d3a641764fddb78 + checksum: c9b285b965c054d4ffd511fd31c18b3d1512dfdf2af0f0340b19a225716aedc2a26d87dadc2dd27b33e2fa6cbcdacff2bb8bf70f91978b2ef3b18dfa327afdfb languageName: node linkType: hard @@ -5357,6 +5357,18 @@ __metadata: languageName: node linkType: hard +"cross-env@npm:^7.0.3": + version: 7.0.3 + resolution: "cross-env@npm:7.0.3" + dependencies: + cross-spawn: "npm:^7.0.1" + bin: + cross-env: src/bin/cross-env.js + cross-env-shell: src/bin/cross-env-shell.js + checksum: e99911f0d31c20e990fd92d6fd001f4b01668a303221227cc5cb42ed155f086351b1b3bd2699b200e527ab13011b032801f8ce638e6f09f854bdf744095e604c + languageName: node + linkType: hard + "cross-spawn@npm:^6.0.5": version: 6.0.5 resolution: "cross-spawn@npm:6.0.5" @@ -5370,7 +5382,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.5": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.5": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -6144,15 +6156,16 @@ __metadata: dependencies: "@1stg/eslint-config": "npm:7.0.1" "@1stg/lib-config": "npm:^12.0.1" - "@changesets/changelog-github": "npm:^0.5.0" + "@changesets/changelog-github": "npm:^0.5.1" "@changesets/cli": "npm:^2.27.12" "@commitlint/cli": "npm:^17.8.1" "@mozilla/glean": "npm:^3.0.0" "@nolyfill/is-core-module": "npm:1.0.39" "@pkgr/rollup": "npm:^4.1.3" "@types/debug": "npm:^4.1.12" - "@types/node": "npm:^18.19.74" + "@types/node": "npm:^18.19.78" "@types/unist": "npm:^2.0.11" + cross-env: "npm:^7.0.3" debug: "npm:^4.3.7" dummy.js: "link:dummy.js" enhanced-resolve: "npm:^5.15.0" @@ -6172,7 +6185,7 @@ __metadata: stable-hash: "npm:^0.0.4" tinyglobby: "npm:^0.2.12" type-coverage: "npm:^2.27.0" - typescript: "npm:^5.3.2" + typescript: "npm:~5.1.0" peerDependencies: eslint: "*" eslint-plugin-import: "*" @@ -13857,6 +13870,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:~5.1.0": + version: 5.1.6 + resolution: "typescript@npm:5.1.6" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: f347cde665cf43dc4c1c7d9821c7d9bbec3c3914f4bdd82ee490e9fb9f6d99036ed8666463b6a192dd005eeef333c5087d5931bdd51ec853436ff9a670a7417e + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A^4.6.4 || ^5.2.2#optional!builtin, typescript@patch:typescript@npm%3A^5.3.2#optional!builtin": version: 5.3.2 resolution: "typescript@patch:typescript@npm%3A5.3.2#optional!builtin::version=5.3.2&hash=e012d7" @@ -13867,6 +13890,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A~5.1.0#optional!builtin": + version: 5.1.6 + resolution: "typescript@patch:typescript@npm%3A5.1.6#optional!builtin::version=5.1.6&hash=5da071" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: f5481fa3ba0eee8970f46708d13c05650a865ad093b586fc9573f425c64c57ca97e3308e110bb528deb3ccebe83f6fd7b5a8ac90018038da96326a9ccdf8e77c + languageName: node + linkType: hard + "unassert@npm:^2.0.0, unassert@npm:^2.0.2": version: 2.0.2 resolution: "unassert@npm:2.0.2"