Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 1 | 'use strict'; |
| 2 | exports.__esModule = true; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 3 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 4 | const pkgDir = require('pkg-dir'); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 5 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 6 | const fs = require('fs'); |
| 7 | const Module = require('module'); |
| 8 | const path = require('path'); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 9 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 10 | const hashObject = require('./hash').hashObject; |
| 11 | const ModuleCache = require('./ModuleCache').default; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 12 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 13 | const CASE_SENSITIVE_FS = !fs.existsSync(path.join(__dirname.toUpperCase(), 'reSOLVE.js')); |
| 14 | exports.CASE_SENSITIVE_FS = CASE_SENSITIVE_FS; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 15 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 16 | const ERROR_NAME = 'EslintPluginImportResolveError'; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 17 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 18 | const fileExistsCache = new ModuleCache(); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 19 | |
| 20 | // Polyfill Node's `Module.createRequireFromPath` if not present (added in Node v10.12.0) |
| 21 | // Use `Module.createRequire` if available (added in Node v12.2.0) |
| 22 | const createRequire = Module.createRequire || Module.createRequireFromPath || function (filename) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 23 | const mod = new Module(filename, null); |
| 24 | mod.filename = filename; |
| 25 | mod.paths = Module._nodeModulePaths(path.dirname(filename)); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 26 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 27 | mod._compile(`module.exports = require;`, filename); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 28 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 29 | return mod.exports; |
| 30 | }; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 31 | |
| 32 | function tryRequire(target, sourceFile) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 33 | let resolved; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 34 | try { |
| 35 | // Check if the target exists |
| 36 | if (sourceFile != null) { |
| 37 | try { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 38 | resolved = createRequire(path.resolve(sourceFile)).resolve(target); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 39 | } catch (e) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 40 | resolved = require.resolve(target); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 41 | } |
| 42 | } else { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 43 | resolved = require.resolve(target); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 44 | } |
| 45 | } catch(e) { |
| 46 | // If the target does not exist then just return undefined |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 47 | return undefined; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | // If the target exists then return the loaded module |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 51 | return require(resolved); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | // http://stackoverflow.com/a/27382838 |
| 55 | exports.fileExistsWithCaseSync = function fileExistsWithCaseSync(filepath, cacheSettings) { |
| 56 | // don't care if the FS is case-sensitive |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 57 | if (CASE_SENSITIVE_FS) return true; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 58 | |
| 59 | // null means it resolved to a builtin |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 60 | if (filepath === null) return true; |
| 61 | if (filepath.toLowerCase() === process.cwd().toLowerCase()) return true; |
| 62 | const parsedPath = path.parse(filepath); |
| 63 | const dir = parsedPath.dir; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 64 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 65 | let result = fileExistsCache.get(filepath, cacheSettings); |
| 66 | if (result != null) return result; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 67 | |
| 68 | // base case |
| 69 | if (dir === '' || parsedPath.root === filepath) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 70 | result = true; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 71 | } else { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 72 | const filenames = fs.readdirSync(dir); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 73 | if (filenames.indexOf(parsedPath.base) === -1) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 74 | result = false; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 75 | } else { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 76 | result = fileExistsWithCaseSync(dir, cacheSettings); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 77 | } |
| 78 | } |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 79 | fileExistsCache.set(filepath, result); |
| 80 | return result; |
| 81 | }; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 82 | |
| 83 | function relative(modulePath, sourceFile, settings) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 84 | return fullResolve(modulePath, sourceFile, settings).path; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | function fullResolve(modulePath, sourceFile, settings) { |
| 88 | // check if this is a bonus core module |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 89 | const coreSet = new Set(settings['import/core-modules']); |
| 90 | if (coreSet.has(modulePath)) return { found: true, path: null }; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 91 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 92 | const sourceDir = path.dirname(sourceFile); |
| 93 | const cacheKey = sourceDir + hashObject(settings).digest('hex') + modulePath; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 94 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 95 | const cacheSettings = ModuleCache.getSettings(settings); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 96 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 97 | const cachedPath = fileExistsCache.get(cacheKey, cacheSettings); |
| 98 | if (cachedPath !== undefined) return { found: true, path: cachedPath }; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 99 | |
| 100 | function cache(resolvedPath) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 101 | fileExistsCache.set(cacheKey, resolvedPath); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 102 | } |
| 103 | |
| 104 | function withResolver(resolver, config) { |
| 105 | |
| 106 | function v1() { |
| 107 | try { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 108 | const resolved = resolver.resolveImport(modulePath, sourceFile, config); |
| 109 | if (resolved === undefined) return { found: false }; |
| 110 | return { found: true, path: resolved }; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 111 | } catch (err) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 112 | return { found: false }; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | |
| 116 | function v2() { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 117 | return resolver.resolve(modulePath, sourceFile, config); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | switch (resolver.interfaceVersion) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 121 | case 2: |
| 122 | return v2(); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 123 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 124 | default: |
| 125 | case 1: |
| 126 | return v1(); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 127 | } |
| 128 | } |
| 129 | |
| 130 | const configResolvers = (settings['import/resolver'] |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 131 | || { 'node': settings['import/resolve'] }); // backward compatibility |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 132 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 133 | const resolvers = resolverReducer(configResolvers, new Map()); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 134 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 135 | for (const pair of resolvers) { |
| 136 | const name = pair[0]; |
| 137 | const config = pair[1]; |
| 138 | const resolver = requireResolver(name, sourceFile); |
| 139 | const resolved = withResolver(resolver, config); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 140 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 141 | if (!resolved.found) continue; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 142 | |
| 143 | // else, counts |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 144 | cache(resolved.path); |
| 145 | return resolved; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | // failed |
| 149 | // cache(undefined) |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 150 | return { found: false }; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 151 | } |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 152 | exports.relative = relative; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 153 | |
| 154 | function resolverReducer(resolvers, map) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 155 | if (Array.isArray(resolvers)) { |
| 156 | resolvers.forEach(r => resolverReducer(r, map)); |
| 157 | return map; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | if (typeof resolvers === 'string') { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 161 | map.set(resolvers, null); |
| 162 | return map; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | if (typeof resolvers === 'object') { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 166 | for (const key in resolvers) { |
| 167 | map.set(key, resolvers[key]); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 168 | } |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 169 | return map; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 170 | } |
| 171 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 172 | const err = new Error('invalid resolver config'); |
| 173 | err.name = ERROR_NAME; |
| 174 | throw err; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 175 | } |
| 176 | |
| 177 | function getBaseDir(sourceFile) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 178 | return pkgDir.sync(sourceFile) || process.cwd(); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 179 | } |
| 180 | function requireResolver(name, sourceFile) { |
| 181 | // Try to resolve package with conventional name |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 182 | const resolver = tryRequire(`eslint-import-resolver-${name}`, sourceFile) || |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 183 | tryRequire(name, sourceFile) || |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 184 | tryRequire(path.resolve(getBaseDir(sourceFile), name)); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 185 | |
| 186 | if (!resolver) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 187 | const err = new Error(`unable to load resolver "${name}".`); |
| 188 | err.name = ERROR_NAME; |
| 189 | throw err; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 190 | } |
| 191 | if (!isResolverValid(resolver)) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 192 | const err = new Error(`${name} with invalid interface loaded as resolver`); |
| 193 | err.name = ERROR_NAME; |
| 194 | throw err; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 195 | } |
| 196 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 197 | return resolver; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | function isResolverValid(resolver) { |
| 201 | if (resolver.interfaceVersion === 2) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 202 | return resolver.resolve && typeof resolver.resolve === 'function'; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 203 | } else { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 204 | return resolver.resolveImport && typeof resolver.resolveImport === 'function'; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 205 | } |
| 206 | } |
| 207 | |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 208 | const erroredContexts = new Set(); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 209 | |
| 210 | /** |
| 211 | * Given |
| 212 | * @param {string} p - module path |
| 213 | * @param {object} context - ESLint context |
| 214 | * @return {string} - the full module filesystem path; |
| 215 | * null if package is core; |
| 216 | * undefined if not found |
| 217 | */ |
| 218 | function resolve(p, context) { |
| 219 | try { |
| 220 | return relative( p |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 221 | , context.getFilename() |
| 222 | , context.settings |
| 223 | ); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 224 | } catch (err) { |
| 225 | if (!erroredContexts.has(context)) { |
| 226 | // The `err.stack` string starts with `err.name` followed by colon and `err.message`. |
| 227 | // We're filtering out the default `err.name` because it adds little value to the message. |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 228 | let errMessage = err.message; |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 229 | if (err.name !== ERROR_NAME && err.stack) { |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 230 | errMessage = err.stack.replace(/^Error: /, ''); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 231 | } |
| 232 | context.report({ |
| 233 | message: `Resolve error: ${errMessage}`, |
| 234 | loc: { line: 1, column: 0 }, |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 235 | }); |
| 236 | erroredContexts.add(context); |
Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 237 | } |
| 238 | } |
| 239 | } |
Tim van der Lippe | 2c89197 | 2021-07-29 16:22:50 +0100 | [diff] [blame^] | 240 | resolve.relative = relative; |
| 241 | exports.default = resolve; |