UNPKG

4.99 kBJavaScriptView Raw
1"use strict"
2exports.__esModule = true
3
4const pkgDir = require('pkg-dir')
5
6const fs = require('fs')
7const path = require('path')
8
9const hashObject = require('./hash').hashObject
10 , ModuleCache = require('./ModuleCache').default
11
12const CASE_SENSITIVE_FS = !fs.existsSync(path.join(__dirname, 'reSOLVE.js'))
13exports.CASE_SENSITIVE_FS = CASE_SENSITIVE_FS
14
15const fileExistsCache = new ModuleCache()
16
17// http://stackoverflow.com/a/27382838
18exports.fileExistsWithCaseSync = function fileExistsWithCaseSync(filepath, cacheSettings) {
19 // don't care if the FS is case-sensitive
20 if (CASE_SENSITIVE_FS) return true
21
22 // null means it resolved to a builtin
23 if (filepath === null) return true
24 const parsedPath = path.parse(filepath)
25 , dir = parsedPath.dir
26
27 let result = fileExistsCache.get(filepath, cacheSettings)
28 if (result != null) return result
29
30 // base case
31 if (dir === '' || parsedPath.root === filepath) {
32 result = true
33 } else {
34 const filenames = fs.readdirSync(dir)
35 if (filenames.indexOf(parsedPath.base) === -1) {
36 result = false
37 } else {
38 result = fileExistsWithCaseSync(dir, cacheSettings)
39 }
40 }
41 fileExistsCache.set(filepath, result)
42 return result
43}
44
45function relative(modulePath, sourceFile, settings) {
46 return fullResolve(modulePath, sourceFile, settings).path
47}
48
49function fullResolve(modulePath, sourceFile, settings) {
50 // check if this is a bonus core module
51 const coreSet = new Set(settings['import/core-modules'])
52 if (coreSet != null && coreSet.has(modulePath)) return { found: true, path: null }
53
54 const sourceDir = path.dirname(sourceFile)
55 , cacheKey = sourceDir + hashObject(settings).digest('hex') + modulePath
56
57 const cacheSettings = ModuleCache.getSettings(settings)
58
59 const cachedPath = fileExistsCache.get(cacheKey, cacheSettings)
60 if (cachedPath !== undefined) return { found: true, path: cachedPath }
61
62 function cache(resolvedPath) {
63 fileExistsCache.set(cacheKey, resolvedPath)
64 }
65
66 function withResolver(resolver, config) {
67
68 function v1() {
69 try {
70 const resolved = resolver.resolveImport(modulePath, sourceFile, config)
71 if (resolved === undefined) return { found: false }
72 return { found: true, path: resolved }
73 } catch (err) {
74 return { found: false }
75 }
76 }
77
78 function v2() {
79 return resolver.resolve(modulePath, sourceFile, config)
80 }
81
82 switch (resolver.interfaceVersion) {
83 case 2:
84 return v2()
85
86 default:
87 case 1:
88 return v1()
89 }
90 }
91
92 const configResolvers = (settings['import/resolver']
93 || { 'node': settings['import/resolve'] }) // backward compatibility
94
95 const resolvers = resolverReducer(configResolvers, new Map())
96
97 for (let pair of resolvers) {
98 let name = pair[0]
99 , config = pair[1]
100 const resolver = requireResolver(name, sourceFile)
101 , resolved = withResolver(resolver, config)
102
103 if (!resolved.found) continue
104
105 // else, counts
106 cache(resolved.path)
107 return resolved
108 }
109
110 // failed
111 // cache(undefined)
112 return { found: false }
113}
114exports.relative = relative
115
116function resolverReducer(resolvers, map) {
117 if (resolvers instanceof Array) {
118 resolvers.forEach(r => resolverReducer(r, map))
119 return map
120 }
121
122 if (typeof resolvers === 'string') {
123 map.set(resolvers, null)
124 return map
125 }
126
127 if (typeof resolvers === 'object') {
128 for (let key in resolvers) {
129 map.set(key, resolvers[key])
130 }
131 return map
132 }
133
134 throw new Error('invalid resolver config')
135}
136
137function requireResolver(name, sourceFile) {
138 // Try to resolve package with conventional name
139 try {
140 return require(`eslint-import-resolver-${name}`)
141 } catch (err) { /* continue */ }
142
143 // Try to resolve package with custom name (@myorg/resolver-name)
144 try {
145 return require(name)
146 } catch (err) { /* continue */ }
147
148 // Try to resolve package with path, relative to closest package.json
149 // or current working directory
150 try {
151 const baseDir = pkgDir.sync(sourceFile) || process.cwd()
152 // absolute paths ignore base, so this covers both
153 return require(path.resolve(baseDir, name))
154 } catch (err) { /* continue */ }
155
156 // all else failed
157 throw new Error(`unable to load resolver "${name}".`)
158}
159
160const erroredContexts = new Set()
161
162/**
163 * Given
164 * @param {string} p - module path
165 * @param {object} context - ESLint context
166 * @return {string} - the full module filesystem path;
167 * null if package is core;
168 * undefined if not found
169 */
170function resolve(p, context) {
171 try {
172 return relative( p
173 , context.getFilename()
174 , context.settings
175 )
176 } catch (err) {
177 if (!erroredContexts.has(context)) {
178 context.report({
179 message: `Resolve error: ${err.message}`,
180 loc: { line: 1, column: 0 },
181 })
182 erroredContexts.add(context)
183 }
184 }
185}
186resolve.relative = relative
187exports.default = resolve