UNPKG

4.03 kBJavaScriptView Raw
1"use strict"
2exports.__esModule = true
3
4const fs = require('fs')
5const path = require('path')
6
7const hashObject = require('./hash').hashObject
8 , ModuleCache = require('./ModuleCache').default
9
10const CASE_INSENSITIVE = fs.existsSync(path.join(__dirname, 'reSOLVE.js'))
11exports.CASE_INSENSITIVE = CASE_INSENSITIVE
12
13const fileExistsCache = new ModuleCache()
14
15// http://stackoverflow.com/a/27382838
16function fileExistsWithCaseSync(filepath, cacheSettings) {
17 const dir = path.dirname(filepath)
18
19 let result = fileExistsCache.get(filepath, cacheSettings)
20 if (result != null) return result
21
22 // base case
23 if (dir === '/' || dir === '.' || /^[A-Z]:\\$/i.test(dir)) {
24 result = true
25 } else {
26 const filenames = fs.readdirSync(dir)
27 if (filenames.indexOf(path.basename(filepath)) === -1) {
28 result = false
29 } else {
30 result = fileExistsWithCaseSync(dir, cacheSettings)
31 }
32 }
33 fileExistsCache.set(filepath, result)
34 return result
35}
36
37function relative(modulePath, sourceFile, settings) {
38
39 const sourceDir = path.dirname(sourceFile)
40 , cacheKey = sourceDir + hashObject(settings).digest('hex') + modulePath
41
42 const cacheSettings = ModuleCache.getSettings(settings)
43
44 const cachedPath = fileExistsCache.get(cacheKey, cacheSettings)
45 if (cachedPath !== undefined) return cachedPath
46
47 function cache(p) {
48 fileExistsCache.set(cacheKey, p)
49 return p
50 }
51
52 function withResolver(resolver, config) {
53
54 function v1() {
55 try {
56 const path = resolver.resolveImport(modulePath, sourceFile, config)
57 if (path === undefined) return { found: false }
58 return { found: true, path }
59 } catch (err) {
60 return { found: false }
61 }
62 }
63
64 function v2() {
65 return resolver.resolve(modulePath, sourceFile, config)
66 }
67
68 switch (resolver.interfaceVersion) {
69 case 2:
70 return v2()
71
72 default:
73 case 1:
74 return v1()
75 }
76 }
77
78 const configResolvers = (settings['import/resolver']
79 || { 'node': settings['import/resolve'] }) // backward compatibility
80
81 const resolvers = resolverReducer(configResolvers, new Map())
82
83 for (let pair of resolvers) {
84 let name = pair[0]
85 , config = pair[1]
86
87 const resolver = requireResolver(name)
88
89 const resolved = withResolver(resolver, config)
90 let resolvedPath = resolved.path
91
92 // resolvers imply file existence, this double-check just ensures the case matches
93 if (resolved.found && CASE_INSENSITIVE && !fileExistsWithCaseSync(resolvedPath, cacheSettings)) {
94 // reject resolved path
95 resolvedPath = undefined
96 }
97
98 if (resolved.found) return cache(resolvedPath)
99 }
100
101 return cache(undefined)
102}
103exports.relative = relative
104
105function resolverReducer(resolvers, map) {
106 if (resolvers instanceof Array) {
107 resolvers.forEach(r => resolverReducer(r, map))
108 return map
109 }
110
111 if (typeof resolvers === 'string') {
112 map.set(resolvers, null)
113 return map
114 }
115
116 if (typeof resolvers === 'object') {
117 for (let key in resolvers) {
118 map.set(key, resolvers[key])
119 }
120 return map
121 }
122
123 throw new Error('invalid resolver config')
124}
125
126function requireResolver(name) {
127 try {
128 return require(`eslint-import-resolver-${name}`)
129 } catch (err) {
130 throw new Error(`unable to load resolver "${name}".`)
131 }
132}
133
134const erroredContexts = new Set()
135
136/**
137 * Given
138 * @param {string} p - module path
139 * @param {object} context - ESLint context
140 * @return {string} - the full module filesystem path;
141 * null if package is core;
142 * undefined if not found
143 */
144function resolve(p, context) {
145 try {
146 return relative( p
147 , context.getFilename()
148 , context.settings
149 )
150 } catch (err) {
151 if (!erroredContexts.has(context)) {
152 context.report({
153 message: `Resolve error: ${err.message}`,
154 loc: { line: 1, col: 0 },
155 })
156 erroredContexts.add(context)
157 }
158 }
159}
160resolve.relative = relative
161exports.default = resolve