Skip to content

Commit

Permalink
Update based on PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
D4N14L committed Sep 25, 2023
1 parent 60e5127 commit cb29496
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 12 deletions.
31 changes: 19 additions & 12 deletions eslint/eslint-patch/src/_patch-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ const fs = require('fs');
const isModuleResolutionError: (ex: unknown) => boolean = (ex) =>
typeof ex === 'object' && !!ex && 'code' in ex && (ex as { code: unknown }).code === 'MODULE_NOT_FOUND';

// error: "The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ''"
const isInvalidImporterPath: (ex: unknown) => boolean = (ex) =>
(ex as { code: unknown } | undefined)?.code === 'ERR_INVALID_ARG_VALUE';

// Module path for eslintrc.cjs
// Example: ".../@eslint/eslintrc/dist/eslintrc.cjs"
let eslintrcBundlePath: string | undefined = undefined;
Expand All @@ -39,7 +35,7 @@ let eslintFolder: string | undefined = undefined;

// Probe for the ESLint >=8.0.0 layout:
for (let currentModule = module; ; ) {
if (!eslintrcBundlePath) {
if (!eslintrcBundlePath && currentModule.filename.endsWith('eslintrc.cjs')) {
// For ESLint >=8.0.0, all @eslint/eslintrc code is bundled at this path:
// .../@eslint/eslintrc/dist/eslintrc.cjs
try {
Expand All @@ -49,8 +45,9 @@ for (let currentModule = module; ; ) {

// Make sure we actually resolved the module in our call path
// and not some other spurious dependency.
if (path.join(eslintrcFolder, 'dist/eslintrc.cjs') === currentModule.filename) {
eslintrcBundlePath = path.join(eslintrcFolder, 'dist/eslintrc.cjs');
const resolvedEslintrcBundlePath: string = path.join(eslintrcFolder, 'dist/eslintrc.cjs');
if (resolvedEslintrcBundlePath === currentModule.filename) {
eslintrcBundlePath = resolvedEslintrcBundlePath;
}
} catch (ex: unknown) {
// Module resolution failures are expected, as we're walking
Expand Down Expand Up @@ -95,7 +92,7 @@ for (let currentModule = module; ; ) {
if (!eslintFolder) {
// Probe for the ESLint >=7.8.0 layout:
for (let currentModule = module; ; ) {
if (!configArrayFactoryPath) {
if (!configArrayFactoryPath && currentModule.filename.endsWith('config-array-factory.js')) {
// For ESLint >=7.8.0, config-array-factory.js is at this path:
// .../@eslint/eslintrc/lib/config-array-factory.js
try {
Expand All @@ -105,8 +102,12 @@ if (!eslintFolder) {
})
);

if (path.join(eslintrcFolder, '/lib/config-array-factory.js') == currentModule.filename) {
configArrayFactoryPath = path.join(eslintrcFolder, 'lib/config-array-factory.js');
const resolvedConfigArrayFactoryPath: string = path.join(
eslintrcFolder,
'/lib/config-array-factory.js'
);
if (resolvedConfigArrayFactoryPath === currentModule.filename) {
configArrayFactoryPath = resolvedConfigArrayFactoryPath;
moduleResolverPath = path.join(eslintrcFolder, 'lib/shared/relative-module-resolver');
namingPath = path.join(eslintrcFolder, 'lib/shared/naming');
}
Expand All @@ -118,7 +119,7 @@ if (!eslintFolder) {
throw ex;
}
}
} else {
} else if (currentModule.filename.endsWith('cli-engine.js')) {
// Next look for a file in ESLint's folder
// .../eslint/lib/cli-engine/cli-engine.js
try {
Expand Down Expand Up @@ -209,4 +210,10 @@ if (eslintMajorVersion === 8) {
Naming = require(namingPath!);
}

export { ConfigArrayFactory, ModuleResolver, Naming, eslintMajorVersion as EslintMajorVersion };
export {
ConfigArrayFactory,
ModuleResolver,
Naming,
eslintMajorVersion as EslintMajorVersion,
isModuleResolutionError
};
45 changes: 45 additions & 0 deletions eslint/eslint-patch/src/custom-config-package-names.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

// This is a workaround for ESLint's requirement to consume shareable configurations from package names prefixed
// with "eslint-config".
//
// To remove this requirement, add this line to the top of your project's .eslintrc.js file:
//
// require("@rushstack/eslint-patch/custom-config-package-names");
//
import { ConfigArrayFactory, ModuleResolver, Naming } from './_patch-base';

if (!ConfigArrayFactory.__loadExtendedShareableConfigPatched) {
ConfigArrayFactory.__loadExtendedShareableConfigPatched = true;
const originalLoadExtendedShareableConfig = ConfigArrayFactory.prototype._loadExtendedShareableConfig;

// Common between ESLint versions
// https://github.com/eslint/eslintrc/blob/242d569020dfe4f561e4503787b99ec016337457/lib/config-array-factory.js#L910
ConfigArrayFactory.prototype._loadExtendedShareableConfig = function (extendName: string) {
const originalResolve = ModuleResolver.resolve;
try {
ModuleResolver.resolve = function (moduleName: string, relativeToPath: string) {
try {
return originalResolve.call(this, moduleName, relativeToPath);
} catch (e) {
// Only change the name we resolve if we cannot find the normalized module, since it is
// valid to rely on the normalized package name. Use the originally provided module path
// instead of the normalized module path.
if (
(e as NodeJS.ErrnoException)?.code === 'MODULE_NOT_FOUND' &&
moduleName !== extendName &&
moduleName === Naming.normalizePackageName(extendName, 'eslint-config')
) {
return originalResolve.call(this, extendName, relativeToPath);
} else {
throw e;
}
}
};
return originalLoadExtendedShareableConfig.apply(this, arguments);
} finally {
ModuleResolver.resolve = originalResolve;
}
};
}
74 changes: 74 additions & 0 deletions eslint/eslint-patch/src/modern-module-resolution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
// This is a workaround for https://github.com/eslint/eslint/issues/3458
//
// To correct how ESLint searches for plugin packages, add this line to the top of your project's .eslintrc.js file:
//
// require("@rushstack/eslint-patch/modern-module-resolution");
//

import {
EslintMajorVersion,
ConfigArrayFactory,
ModuleResolver,
isModuleResolutionError
} from './_patch-base';

// error: "The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received ''"
const isInvalidImporterPath: (ex: unknown) => boolean = (ex) =>
(ex as { code: unknown } | undefined)?.code === 'ERR_INVALID_ARG_VALUE';

if (!ConfigArrayFactory.__loadPluginPatched) {
ConfigArrayFactory.__loadPluginPatched = true;
const originalLoadPlugin = ConfigArrayFactory.prototype._loadPlugin;

if (EslintMajorVersion === 6) {
// ESLint 6.x
// https://github.com/eslint/eslint/blob/9738f8cc864d769988ccf42bb70f524444df1349/lib/cli-engine/config-array-factory.js#L915
ConfigArrayFactory.prototype._loadPlugin = function (
name: string,
importerPath: string,
importerName: string
) {
const originalResolve = ModuleResolver.resolve;
try {
ModuleResolver.resolve = function (moduleName: string, relativeToPath: string) {
try {
// resolve using importerPath instead of relativeToPath
return originalResolve.call(this, moduleName, importerPath);
} catch (e) {
if (isModuleResolutionError(e) || isInvalidImporterPath(e)) {
return originalResolve.call(this, moduleName, relativeToPath);
}
throw e;
}
};
return originalLoadPlugin.apply(this, arguments);
} finally {
ModuleResolver.resolve = originalResolve;
}
};
} else {
// ESLint 7.x || 8.x
// https://github.com/eslint/eslintrc/blob/242d569020dfe4f561e4503787b99ec016337457/lib/config-array-factory.js#L1023
ConfigArrayFactory.prototype._loadPlugin = function (name: string, ctx: Record<string, unknown>) {
const originalResolve = ModuleResolver.resolve;
try {
ModuleResolver.resolve = function (moduleName: string, relativeToPath: string) {
try {
// resolve using ctx.filePath instead of relativeToPath
return originalResolve.call(this, moduleName, ctx.filePath);
} catch (e) {
if (isModuleResolutionError(e) || isInvalidImporterPath(e)) {
return originalResolve.call(this, moduleName, relativeToPath);
}
throw e;
}
};
return originalLoadPlugin.apply(this, arguments);
} finally {
ModuleResolver.resolve = originalResolve;
}
};
}
}

0 comments on commit cb29496

Please sign in to comment.