-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathresolve.js
140 lines (112 loc) · 3.62 KB
/
resolve.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import fs from 'fs'
import { dirname, basename, join } from 'path'
export const CASE_INSENSITIVE = fs.existsSync(join(__dirname, 'reSOLVE.js'))
const fileExistsCache = new Map()
function cachePath(cacheKey, result) {
fileExistsCache.set(cacheKey, { result, lastSeen: Date.now() })
}
function checkCache(cacheKey, { lifetime }) {
if (fileExistsCache.has(cacheKey)) {
const { result, lastSeen } = fileExistsCache.get(cacheKey)
// check fresness
if (Date.now() - lastSeen < (lifetime * 1000)) return result
}
// cache miss
return undefined
}
// http://stackoverflow.com/a/27382838
function fileExistsWithCaseSync(filepath, cacheSettings) {
const dir = dirname(filepath)
let result = checkCache(filepath, cacheSettings)
if (result != null) return result
// base case
if (dir === '/' || dir === '.' || /^[A-Z]:\\$/i.test(dir)) {
result = true
} else {
const filenames = fs.readdirSync(dir)
if (filenames.indexOf(basename(filepath)) === -1) {
result = false
} else {
result = fileExistsWithCaseSync(dir, cacheSettings)
}
}
cachePath(filepath, result)
return result
}
export function relative(modulePath, sourceFile, settings) {
const sourceDir = dirname(sourceFile)
, cacheKey = sourceDir + hashObject(settings) + modulePath
const cacheSettings = Object.assign({
lifetime: 30, // seconds
}, settings['import/cache'])
// parse infinity
if (cacheSettings.lifetime === '∞' || cacheSettings.lifetime === 'Infinity') {
cacheSettings.lifetime = Infinity
}
const cachedPath = checkCache(cacheKey, cacheSettings)
if (cachedPath !== undefined) return cachedPath
function cache(path) {
cachePath(cacheKey, path)
return path
}
function withResolver(resolver, config) {
try {
const filePath = resolver.resolveImport(modulePath, sourceFile, config)
if (filePath == null) return filePath
// resolvers imply file existence, this double-check just ensures the case matches
if (CASE_INSENSITIVE && !fileExistsWithCaseSync(filePath, cacheSettings)) return undefined
return filePath
} catch (err) {
return undefined
}
}
const configResolvers = (settings['import/resolver']
|| { 'node': settings['import/resolve'] }) // backward compatibility
const resolvers = resolverReducer(configResolvers, new Map())
for (let [name, config] of resolvers.entries()) {
const resolver = require(`eslint-import-resolver-${name}`)
let fullPath = withResolver(resolver, config)
if (fullPath !== undefined) {
return cache(fullPath)
}
}
return cache(undefined)
}
function resolverReducer(resolvers, map) {
if (resolvers instanceof Array) {
resolvers.forEach(r => resolverReducer(r, map))
return map
}
if (typeof resolvers === 'string') {
map.set(resolvers, null)
return map
}
if (typeof resolvers === 'object') {
for (let key in resolvers) {
map.set(key, resolvers[key])
}
return map
}
throw new Error('invalid resolver config')
}
/**
* Givent
* @param {string} p - module path
* @param {object} context - ESLint context
* @return {string} - the full module filesystem path;
* null if package is core;
* undefined if not found
*/
export default function resolve(p, context) {
return relative( p
, context.getFilename()
, context.settings
)
}
resolve.relative = relative
import { createHash } from 'crypto'
function hashObject(object) {
const settingsShasum = createHash('sha1')
settingsShasum.update(JSON.stringify(object))
return settingsShasum.digest('hex')
}