You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
9.0 KiB
211 lines
9.0 KiB
"use strict"; |
|
// 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"); |
|
// |
|
const path = require('path'); |
|
const fs = require('fs'); |
|
const isModuleResolutionError = (ex) => typeof ex === 'object' && !!ex && 'code' in ex && ex.code === 'MODULE_NOT_FOUND'; |
|
// Module path for eslintrc.cjs |
|
// Example: ".../@eslint/eslintrc/dist/eslintrc.cjs" |
|
let eslintrcBundlePath = undefined; |
|
// Module path for config-array-factory.js |
|
// Example: ".../@eslint/eslintrc/lib/config-array-factory" |
|
let configArrayFactoryPath = undefined; |
|
// Module path for relative-module-resolver.js |
|
// Example: ".../@eslint/eslintrc/lib/shared/relative-module-resolver" |
|
let moduleResolverPath = undefined; |
|
// Folder path where ESLint's package.json can be found |
|
// Example: ".../node_modules/eslint" |
|
let eslintFolder = undefined; |
|
// Probe for the ESLint >=8.0.0 layout: |
|
for (let currentModule = module;;) { |
|
if (!eslintrcBundlePath) { |
|
// For ESLint >=8.0.0, all @eslint/eslintrc code is bundled at this path: |
|
// .../@eslint/eslintrc/dist/eslintrc.cjs |
|
try { |
|
const eslintrcFolder = path.dirname(require.resolve('@eslint/eslintrc/package.json', { paths: [currentModule.path] })); |
|
// 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'); |
|
} |
|
} |
|
catch (ex) { |
|
// Module resolution failures are expected, as we're walking |
|
// up our require stack to look for eslint. All other errors |
|
// are rethrown. |
|
if (!isModuleResolutionError(ex)) { |
|
throw ex; |
|
} |
|
} |
|
} |
|
else { |
|
// Next look for a file in ESLint's folder |
|
// .../eslint/lib/cli-engine/cli-engine.js |
|
try { |
|
const eslintCandidateFolder = path.dirname(require.resolve('eslint/package.json', { |
|
paths: [currentModule.path] |
|
})); |
|
// Make sure we actually resolved the module in our call path |
|
// and not some other spurious dependency. |
|
if (path.join(eslintCandidateFolder, 'lib/cli-engine/cli-engine.js') === currentModule.filename) { |
|
eslintFolder = eslintCandidateFolder; |
|
break; |
|
} |
|
} |
|
catch (ex) { |
|
// Module resolution failures are expected, as we're walking |
|
// up our require stack to look for eslint. All other errors |
|
// are rethrown. |
|
if (!isModuleResolutionError(ex)) { |
|
throw ex; |
|
} |
|
} |
|
} |
|
if (!currentModule.parent) { |
|
break; |
|
} |
|
currentModule = currentModule.parent; |
|
} |
|
if (!eslintFolder) { |
|
// Probe for the ESLint >=7.8.0 layout: |
|
for (let currentModule = module;;) { |
|
if (!configArrayFactoryPath) { |
|
// For ESLint >=7.8.0, config-array-factory.js is at this path: |
|
// .../@eslint/eslintrc/lib/config-array-factory.js |
|
try { |
|
const eslintrcFolder = path.dirname(require.resolve('@eslint/eslintrc/package.json', { |
|
paths: [currentModule.path] |
|
})); |
|
if (path.join(eslintrcFolder, '/lib/config-array-factory.js') == currentModule.filename) { |
|
configArrayFactoryPath = path.join(eslintrcFolder, 'lib/config-array-factory.js'); |
|
moduleResolverPath = path.join(eslintrcFolder, 'lib/shared/relative-module-resolver'); |
|
} |
|
} |
|
catch (ex) { |
|
// Module resolution failures are expected, as we're walking |
|
// up our require stack to look for eslint. All other errors |
|
// are rethrown. |
|
if (!isModuleResolutionError(ex)) { |
|
throw ex; |
|
} |
|
} |
|
} |
|
else { |
|
// Next look for a file in ESLint's folder |
|
// .../eslint/lib/cli-engine/cli-engine.js |
|
try { |
|
const eslintCandidateFolder = path.dirname(require.resolve('eslint/package.json', { |
|
paths: [currentModule.path] |
|
})); |
|
if (path.join(eslintCandidateFolder, 'lib/cli-engine/cli-engine.js') == currentModule.filename) { |
|
eslintFolder = eslintCandidateFolder; |
|
break; |
|
} |
|
} |
|
catch (ex) { |
|
// Module resolution failures are expected, as we're walking |
|
// up our require stack to look for eslint. All other errors |
|
// are rethrown. |
|
if (!isModuleResolutionError(ex)) { |
|
throw ex; |
|
} |
|
} |
|
} |
|
if (!currentModule.parent) { |
|
break; |
|
} |
|
currentModule = currentModule.parent; |
|
} |
|
} |
|
if (!eslintFolder) { |
|
// Probe for the <7.8.0 layout: |
|
for (let currentModule = module;;) { |
|
// For ESLint <7.8.0, config-array-factory.js was at this path: |
|
// .../eslint/lib/cli-engine/config-array-factory.js |
|
if (/[\\/]eslint[\\/]lib[\\/]cli-engine[\\/]config-array-factory\.js$/i.test(currentModule.filename)) { |
|
eslintFolder = path.join(path.dirname(currentModule.filename), '../..'); |
|
configArrayFactoryPath = path.join(eslintFolder, 'lib/cli-engine/config-array-factory'); |
|
moduleResolverPath = path.join(eslintFolder, 'lib/shared/relative-module-resolver'); |
|
break; |
|
} |
|
if (!currentModule.parent) { |
|
// This was tested with ESLint 6.1.0 .. 7.12.1. |
|
throw new Error('Failed to patch ESLint because the calling module was not recognized.\n' + |
|
'If you are using a newer ESLint version that may be unsupported, please create a GitHub issue:\n' + |
|
'https://github.com/microsoft/rushstack/issues'); |
|
} |
|
currentModule = currentModule.parent; |
|
} |
|
} |
|
// Detect the ESLint package version |
|
const eslintPackageJson = fs.readFileSync(path.join(eslintFolder, 'package.json')).toString(); |
|
const eslintPackageObject = JSON.parse(eslintPackageJson); |
|
const eslintPackageVersion = eslintPackageObject.version; |
|
const versionMatch = /^([0-9]+)\./.exec(eslintPackageVersion); // parse the SemVer MAJOR part |
|
if (!versionMatch) { |
|
throw new Error('Unable to parse ESLint version: ' + eslintPackageVersion); |
|
} |
|
const eslintMajorVersion = Number(versionMatch[1]); |
|
if (!(eslintMajorVersion >= 6 && eslintMajorVersion <= 8)) { |
|
throw new Error('The patch-eslint.js script has only been tested with ESLint version 6.x, 7.x, and 8.x.' + |
|
` (Your version: ${eslintPackageVersion})\n` + |
|
'Consider reporting a GitHub issue:\n' + |
|
'https://github.com/microsoft/rushstack/issues'); |
|
} |
|
let ConfigArrayFactory; |
|
if (eslintMajorVersion === 8) { |
|
ConfigArrayFactory = require(eslintrcBundlePath).Legacy.ConfigArrayFactory; |
|
} |
|
else { |
|
ConfigArrayFactory = require(configArrayFactoryPath).ConfigArrayFactory; |
|
} |
|
if (!ConfigArrayFactory.__patched) { |
|
ConfigArrayFactory.__patched = true; |
|
let ModuleResolver; |
|
if (eslintMajorVersion === 8) { |
|
ModuleResolver = require(eslintrcBundlePath).Legacy.ModuleResolver; |
|
} |
|
else { |
|
ModuleResolver = require(moduleResolverPath); |
|
} |
|
const originalLoadPlugin = ConfigArrayFactory.prototype._loadPlugin; |
|
if (eslintMajorVersion === 6) { |
|
// ESLint 6.x |
|
ConfigArrayFactory.prototype._loadPlugin = function (name, importerPath, importerName) { |
|
const originalResolve = ModuleResolver.resolve; |
|
try { |
|
ModuleResolver.resolve = function (moduleName, relativeToPath) { |
|
// resolve using importerPath instead of relativeToPath |
|
return originalResolve.call(this, moduleName, importerPath); |
|
}; |
|
return originalLoadPlugin.apply(this, arguments); |
|
} |
|
finally { |
|
ModuleResolver.resolve = originalResolve; |
|
} |
|
}; |
|
} |
|
else { |
|
// ESLint 7.x || 8.x |
|
ConfigArrayFactory.prototype._loadPlugin = function (name, ctx) { |
|
const originalResolve = ModuleResolver.resolve; |
|
try { |
|
ModuleResolver.resolve = function (moduleName, relativeToPath) { |
|
// resolve using ctx.filePath instead of relativeToPath |
|
return originalResolve.call(this, moduleName, ctx.filePath); |
|
}; |
|
return originalLoadPlugin.apply(this, arguments); |
|
} |
|
finally { |
|
ModuleResolver.resolve = originalResolve; |
|
} |
|
}; |
|
} |
|
} |
|
//# sourceMappingURL=modern-module-resolution.js.map
|