-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathno-internal-modules.js
102 lines (89 loc) · 3.02 KB
/
no-internal-modules.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
import minimatch from 'minimatch'
import resolve from 'eslint-module-utils/resolve'
import importType from '../core/importType'
import isStaticRequire from '../core/staticRequire'
import docsUrl from '../docsUrl'
module.exports = {
meta: {
type: 'suggestion',
docs: {
url: docsUrl('no-internal-modules'),
},
schema: [
{
type: 'object',
properties: {
allow: {
type: 'array',
items: {
type: 'string',
},
},
},
additionalProperties: false,
},
],
},
create: function noReachingInside(context) {
const options = context.options[0] || {}
const allowRegexps = (options.allow || []).map(p => minimatch.makeRe(p))
// test if reaching to this destination is allowed
function reachingAllowed(importPath) {
return allowRegexps.some(re => re.test(importPath))
}
// minimatch patterns are expected to use / path separators, like import
// statements, so normalize paths to use the same
function normalizeSep(somePath) {
return somePath.split('\\').join('/')
}
// find a directory that is being reached into, but which shouldn't be
function isReachViolation(importPath) {
const steps = normalizeSep(importPath)
.split('/')
.reduce((acc, step) => {
if (!step || step === '.') {
return acc
} else if (step === '..') {
return acc.slice(0, -1)
} else {
return acc.concat(step)
}
}, [])
const nonScopeSteps = steps.filter(step => step.indexOf('@') !== 0)
if (nonScopeSteps.length <= 1) return false
// before trying to resolve, see if the raw import (with relative
// segments resolved) matches an allowed pattern
const justSteps = steps.join('/')
if (reachingAllowed(justSteps) || reachingAllowed(`/${justSteps}`)) return false
// if the import statement doesn't match directly, try to match the
// resolved path if the import is resolvable
const resolved = resolve(importPath, context)
if (!resolved || reachingAllowed(normalizeSep(resolved))) return false
// this import was not allowed by the allowed paths, and reaches
// so it is a violation
return true
}
function checkImportForReaching(importPath, node) {
const potentialViolationTypes = ['parent', 'index', 'sibling', 'external', 'internal']
if (potentialViolationTypes.indexOf(importType(importPath, context)) !== -1 &&
isReachViolation(importPath)
) {
context.report({
node,
message: `Reaching to "${importPath}" is not allowed.`,
})
}
}
return {
ImportDeclaration(node) {
checkImportForReaching(node.source.value, node.source)
},
CallExpression(node) {
if (isStaticRequire(node)) {
const [ firstArgument ] = node.arguments
checkImportForReaching(firstArgument.value, firstArgument)
}
},
}
},
}