UNPKG

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