Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/eslint-plugin-import
Path: blob/main/src/rules/no-commonjs.js
829 views
1
/**
2
* @fileoverview Rule to prefer ES6 to CJS
3
* @author Jamund Ferguson
4
*/
5
6
import docsUrl from '../docsUrl';
7
8
const EXPORT_MESSAGE = 'Expected "export" or "export default"';
9
const IMPORT_MESSAGE = 'Expected "import" instead of "require()"';
10
11
function normalizeLegacyOptions(options) {
12
if (options.indexOf('allow-primitive-modules') >= 0) {
13
return { allowPrimitiveModules: true };
14
}
15
return options[0] || {};
16
}
17
18
function allowPrimitive(node, options) {
19
if (!options.allowPrimitiveModules) return false;
20
if (node.parent.type !== 'AssignmentExpression') return false;
21
return (node.parent.right.type !== 'ObjectExpression');
22
}
23
24
function allowRequire(node, options) {
25
return options.allowRequire;
26
}
27
28
function allowConditionalRequire(node, options) {
29
return options.allowConditionalRequire !== false;
30
}
31
32
function validateScope(scope) {
33
return scope.variableScope.type === 'module';
34
}
35
36
// https://github.com/estree/estree/blob/HEAD/es5.md
37
function isConditional(node) {
38
if (
39
node.type === 'IfStatement'
40
|| node.type === 'TryStatement'
41
|| node.type === 'LogicalExpression'
42
|| node.type === 'ConditionalExpression'
43
) return true;
44
if (node.parent) return isConditional(node.parent);
45
return false;
46
}
47
48
function isLiteralString(node) {
49
return (node.type === 'Literal' && typeof node.value === 'string') ||
50
(node.type === 'TemplateLiteral' && node.expressions.length === 0);
51
}
52
53
//------------------------------------------------------------------------------
54
// Rule Definition
55
//------------------------------------------------------------------------------
56
57
const schemaString = { enum: ['allow-primitive-modules'] };
58
const schemaObject = {
59
type: 'object',
60
properties: {
61
allowPrimitiveModules: { 'type': 'boolean' },
62
allowRequire: { 'type': 'boolean' },
63
allowConditionalRequire: { 'type': 'boolean' },
64
},
65
additionalProperties: false,
66
};
67
68
module.exports = {
69
meta: {
70
type: 'suggestion',
71
docs: {
72
url: docsUrl('no-commonjs'),
73
},
74
75
schema: {
76
anyOf: [
77
{
78
type: 'array',
79
items: [schemaString],
80
additionalItems: false,
81
},
82
{
83
type: 'array',
84
items: [schemaObject],
85
additionalItems: false,
86
},
87
],
88
},
89
},
90
91
create(context) {
92
const options = normalizeLegacyOptions(context.options);
93
94
return {
95
96
'MemberExpression': function (node) {
97
98
// module.exports
99
if (node.object.name === 'module' && node.property.name === 'exports') {
100
if (allowPrimitive(node, options)) return;
101
context.report({ node, message: EXPORT_MESSAGE });
102
}
103
104
// exports.
105
if (node.object.name === 'exports') {
106
const isInScope = context.getScope()
107
.variables
108
.some(variable => variable.name === 'exports');
109
if (! isInScope) {
110
context.report({ node, message: EXPORT_MESSAGE });
111
}
112
}
113
114
},
115
'CallExpression': function (call) {
116
if (!validateScope(context.getScope())) return;
117
118
if (call.callee.type !== 'Identifier') return;
119
if (call.callee.name !== 'require') return;
120
121
if (call.arguments.length !== 1) return;
122
if (!isLiteralString(call.arguments[0])) return;
123
124
if (allowRequire(call, options)) return;
125
126
if (allowConditionalRequire(call, options) && isConditional(call.parent)) return;
127
128
// keeping it simple: all 1-string-arg `require` calls are reported
129
context.report({
130
node: call.callee,
131
message: IMPORT_MESSAGE,
132
});
133
},
134
};
135
136
},
137
};
138
139