Minor Changes
-
#192
fbf639bThanks @SukkaW! - The PR implements the new resolver design proposed in #40 (comment)For
eslint-plugin-import-xusersLike the ESLint flat config allows you to use js objects (e.g. import and require) as ESLint plugins, the new
eslint-plugin-import-xresolver settings allow you to use js objects as custom resolvers through the new settingimport-x/resolver-next:// eslint.config.js import { createTsResolver } from '#custom-resolver'; const { createOxcResolver } = require('path/to/a/custom/resolver'); const resolverInstance = new ResolverFactory({}); const customResolverObject = { interfaceVersion: 3, name: 'my-custom-eslint-import-resolver', resolve(modPath, sourcePath) { const path = resolverInstance.resolve(modPath, sourcePath); if (path) { return { found: true, path }; } return { found: false, path: null } }; }; module.exports = { settings: { // multiple resolvers 'import-x/resolver-next': [ customResolverObject, createTsResolver(enhancedResolverOptions), createOxcResolver(oxcOptions), ], // single resolver: 'import-x/resolver-next': [createOxcResolver(oxcOptions)] } }
The new
import-x/resolver-nextno longer accepts strings as the resolver, thus will not be compatible with the ESLint legacy config (a.k.a..eslintrc). Those who are still using the ESLint legacy config should stick withimport-x/resolver.In the next major version of
eslint-plugin-import-x(v5), we will rename the currently existingimport-x/resolvertoimport-x/resolver-legacy(which allows the existing ESLint legacy config users to use their existing resolver settings), andimport-x/resolver-nextwill become the newimport-x/resolver. When ESLint v9 (the last ESLint version with ESLint legacy config support) reaches EOL in the future, we will removeimport-x/resolver-legacy.We have also made a few breaking changes to the new resolver API design, so you can't use existing custom resolvers directly with
import-x/resolver-next:// When migrating to `import-x/resolver-next`, you CAN'T use legacy versions of resolvers directly: module.exports = { settings: { // THIS WON'T WORK, the resolver interface required for `import-x/resolver-next` is different. 'import-x/resolver-next': [ require('eslint-import-resolver-node'), require('eslint-import-resolver-webpack'), require('some-custom-resolver') ]; } }
For easier migration, the PR also introduces a compat utility
importXResolverCompatthat you can use in youreslint.config.js:// eslint.config.js import eslintPluginImportX, { importXResolverCompat } from 'eslint-plugin-import-x'; // or const eslintPluginImportX = require('eslint-plugin-import-x'); const { importXResolverCompat } = eslintPluginImportX; module.exports = { settings: { // THIS WILL WORK as you have wrapped the previous version of resolvers with the `importXResolverCompat` 'import-x/resolver-next': [ importXResolverCompat(require('eslint-import-resolver-node'), nodeResolveOptions), importXResolverCompat(require('eslint-import-resolver-webpack'), webpackResolveOptions), importXResolverCompat(require('some-custom-resolver'), { option1: true, option2: '' }) ]; } }
For custom import resolver developers
This is the new API design of the resolver interface:
export interface NewResolver { interfaceVersion: 3; name?: string; // This will be included in the debug log resolve: (modulePath: string, sourceFile: string) => ResolvedResult; } // The `ResultNotFound` (returned when not resolved) is the same, no changes export interface ResultNotFound { found: false; path?: undefined; } // The `ResultFound` (returned resolve result) is also the same, no changes export interface ResultFound { found: true; path: string | null; } export type ResolvedResult = ResultNotFound | ResultFound;
You will be able to import
NewResolverfromeslint-plugin-import-x/types.The most notable change is that
eslint-plugin-import-xno longer passes the third argument (options) to theresolvefunction.We encourage custom resolvers' authors to consume the options outside the actual
resolvefunction implementation. You can export a factory function to accept the options, this factory function will then be called inside theeslint.config.jsto get the actual resolver:// custom-resolver.js exports.createCustomResolver = (options) => { // The options are consumed outside the `resolve` function. const resolverInstance = new ResolverFactory(options); return { name: 'custom-resolver', interfaceVersion: 3, resolve(mod, source) { const found = resolverInstance.resolve(mod, {}); // Of course, you still have access to the `options` variable here inside // the `resolve` function. That's the power of JavaScript Closures~ } } }; // eslint.config.js const { createCustomResolver } = require('custom-resolver') module.exports = { settings: { 'import-x/resolver-next': [ createCustomResolver(options) ]; } }
This allows you to create a reusable resolver instance to improve the performance. With the existing version of the resolver interface, because the options are passed to the
resolverfunction, you will have to create a resolver instance every time theresolvefunction is called:module.exports = { interfaceVersion: 2, resolve(mod, source) { // every time the `resolve` function is called, a new instance is created // This is very slow const resolverInstance = ResolverFactory.createResolver({}); const found = resolverInstance.resolve(mod, {}); }, };
With the factory function pattern, you can create a resolver instance beforehand:
exports.createCustomResolver = (options) => { // `enhance-resolve` allows you to create a reusable instance: const resolverInstance = ResolverFactory.createResolver({}); const resolverInstance = enhanceResolve.create({}); // `oxc-resolver` also allows you to create a reusable instance: const resolverInstance = new ResolverFactory({}); return { name: "custom-resolver", interfaceVersion: 3, resolve(mod, source) { // the same re-usable instance is shared across `resolve` invocations. // more performant const found = resolverInstance.resolve(mod, {}); }, }; };
Patch Changes
-
#184
bc4de89Thanks @marcalexiei! - fix(no-cycle): improves the type declaration of the ruleno-cycle’smaxDepthoption -
#184
bc4de89Thanks @marcalexiei! - fix(first): improves the type declaration of the rulefirst's option -
#184
bc4de89Thanks @marcalexiei! - fix(no-unused-modules): improves the type declaration of the ruleno-unused-modules’smissingExportsoption -
#184
bc4de89Thanks @marcalexiei! - fix(no-deprecated): improve error message when no description is available
Full Changelog: v4.4.3...v4.5.0