Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/eslint-plugin-import
Path: blob/main/src/rules/no-internal-modules.js
829 views
1
import minimatch from 'minimatch';
2
3
import resolve from 'eslint-module-utils/resolve';
4
import importType from '../core/importType';
5
import moduleVisitor from 'eslint-module-utils/moduleVisitor';
6
import docsUrl from '../docsUrl';
7
8
module.exports = {
9
meta: {
10
type: 'suggestion',
11
docs: {
12
url: docsUrl('no-internal-modules'),
13
},
14
15
schema: [
16
{
17
oneOf: [
18
{
19
type: 'object',
20
properties: {
21
allow: {
22
type: 'array',
23
items: {
24
type: 'string',
25
},
26
},
27
},
28
additionalProperties: false,
29
},
30
{
31
type: 'object',
32
properties: {
33
forbid: {
34
type: 'array',
35
items: {
36
type: 'string',
37
},
38
},
39
},
40
additionalProperties: false,
41
},
42
],
43
},
44
],
45
},
46
47
create: function noReachingInside(context) {
48
const options = context.options[0] || {};
49
const allowRegexps = (options.allow || []).map(p => minimatch.makeRe(p));
50
const forbidRegexps = (options.forbid || []).map(p => minimatch.makeRe(p));
51
52
// minimatch patterns are expected to use / path separators, like import
53
// statements, so normalize paths to use the same
54
function normalizeSep(somePath) {
55
return somePath.split('\\').join('/');
56
}
57
58
function toSteps(somePath) {
59
return normalizeSep(somePath)
60
.split('/')
61
.reduce((acc, step) => {
62
if (!step || step === '.') {
63
return acc;
64
} else if (step === '..') {
65
return acc.slice(0, -1);
66
} else {
67
return acc.concat(step);
68
}
69
}, []);
70
}
71
72
// test if reaching to this destination is allowed
73
function reachingAllowed(importPath) {
74
return allowRegexps.some(re => re.test(importPath));
75
}
76
77
// test if reaching to this destination is forbidden
78
function reachingForbidden(importPath) {
79
return forbidRegexps.some(re => re.test(importPath));
80
}
81
82
function isAllowViolation(importPath) {
83
const steps = toSteps(importPath);
84
85
const nonScopeSteps = steps.filter(step => step.indexOf('@') !== 0);
86
if (nonScopeSteps.length <= 1) return false;
87
88
// before trying to resolve, see if the raw import (with relative
89
// segments resolved) matches an allowed pattern
90
const justSteps = steps.join('/');
91
if (reachingAllowed(justSteps) || reachingAllowed(`/${justSteps}`)) return false;
92
93
// if the import statement doesn't match directly, try to match the
94
// resolved path if the import is resolvable
95
const resolved = resolve(importPath, context);
96
if (!resolved || reachingAllowed(normalizeSep(resolved))) return false;
97
98
// this import was not allowed by the allowed paths, and reaches
99
// so it is a violation
100
return true;
101
}
102
103
function isForbidViolation(importPath) {
104
const steps = toSteps(importPath);
105
106
// before trying to resolve, see if the raw import (with relative
107
// segments resolved) matches a forbidden pattern
108
const justSteps = steps.join('/');
109
110
if (reachingForbidden(justSteps) || reachingForbidden(`/${justSteps}`)) return true;
111
112
// if the import statement doesn't match directly, try to match the
113
// resolved path if the import is resolvable
114
const resolved = resolve(importPath, context);
115
if (resolved && reachingForbidden(normalizeSep(resolved))) return true;
116
117
// this import was not forbidden by the forbidden paths so it is not a violation
118
return false;
119
}
120
121
// find a directory that is being reached into, but which shouldn't be
122
const isReachViolation = options.forbid ? isForbidViolation : isAllowViolation;
123
124
function checkImportForReaching(importPath, node) {
125
const potentialViolationTypes = ['parent', 'index', 'sibling', 'external', 'internal'];
126
if (potentialViolationTypes.indexOf(importType(importPath, context)) !== -1 &&
127
isReachViolation(importPath)
128
) {
129
context.report({
130
node,
131
message: `Reaching to "${importPath}" is not allowed.`,
132
});
133
}
134
}
135
136
return moduleVisitor((source) => {
137
checkImportForReaching(source.value, source);
138
}, { commonjs: true });
139
},
140
};
141
142