Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions src/getESLint.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createRequire } from 'node:module';
import path from 'node:path';
import { pathToFileURL } from 'node:url';

import { getESLintOptions } from './options.js';
Expand Down Expand Up @@ -62,6 +63,10 @@ async function getESLint(options) {
* @returns {Promise<Record<string, any>>}
*/
async function loadESLintModule(specifier) {
if (isAbsolutePathSpecifier(specifier)) {
return loadResolvedModule(specifier);
}

try {
// Prefer native ESM resolution for package specifiers so conditional
// exports use the import-compatible entry.
Expand All @@ -73,11 +78,27 @@ async function loadESLintModule(specifier) {

// Fall back to CommonJS resolution only for legacy path-style eslintPath
// values, such as directories that ESM import cannot resolve directly.
const resolvedPath = moduleRequire.resolve(specifier);
return normalizeModule(await import(pathToFileURL(resolvedPath).href));
return loadResolvedModule(specifier);
}
}

/**
* @param {string} specifier
* @returns {Promise<Record<string, any>>}
*/
async function loadResolvedModule(specifier) {
const resolvedPath = moduleRequire.resolve(specifier);
return normalizeModule(await import(pathToFileURL(resolvedPath).href));
}

/**
* @param {string} specifier
* @returns {boolean}
*/
function isAbsolutePathSpecifier(specifier) {
return path.isAbsolute(specifier) || path.win32.isAbsolute(specifier);
}

/**
* @param {unknown} error
* @returns {boolean}
Expand Down
11 changes: 11 additions & 0 deletions test/eslint-path.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ describe('eslint path', () => {
expect(stats.compilation.errors[0].message).toContain('Fake error');
});

it('should use eslint from an absolute file path', async () => {
const eslintPath = join(import.meta.dirname, 'mock/eslint/index.js');

const { eslint } = await getESLint({
eslintPath,
configType: 'flat',
});

expect(eslint).toBeTruthy();
Comment thread
chenjiahan marked this conversation as resolved.
});

it('should fail with a clear error when eslintPath does not export loadESLint', async () => {
const eslintPath = join(import.meta.dirname, 'mock/eslint-no-load');

Expand Down
Loading