forked from mysticatea/eslint-plugin-node
-
-
Notifications
You must be signed in to change notification settings - Fork 41
/
no-exports-assign.js
87 lines (78 loc) · 2.69 KB
/
no-exports-assign.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
/**
* @author Toru Nagashima <https://github.com/mysticatea>
* See LICENSE file in root directory for full license.
*/
"use strict"
const { findVariable } = require("@eslint-community/eslint-utils")
/**
* @param {import('estree').Node} node
* @param {import('eslint').Scope.Scope} scope
* @returns {boolean}
*/
function isExports(node, scope) {
let variable = null
return (
node != null &&
node.type === "Identifier" &&
node.name === "exports" &&
(variable = findVariable(scope, node)) != null &&
variable.scope.type === "global"
)
}
/**
* @param {import('estree').Node} node
* @param {import('eslint').Scope.Scope} scope
* @returns {boolean}
*/
function isModuleExports(node, scope) {
let variable = null
return (
node != null &&
node.type === "MemberExpression" &&
!node.computed &&
node.object.type === "Identifier" &&
node.object.name === "module" &&
node.property.type === "Identifier" &&
node.property.name === "exports" &&
(variable = findVariable(scope, node.object)) != null &&
variable.scope.type === "global"
)
}
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
docs: {
description: "disallow the assignment to `exports`",
recommended: true,
url: "https://github.com/eslint-community/eslint-plugin-n/blob/HEAD/docs/rules/no-exports-assign.md",
},
fixable: null,
messages: {
forbidden:
"Unexpected assignment to 'exports' variable. Use 'module.exports' instead.",
},
schema: [],
type: "problem",
},
create(context) {
const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9
return {
AssignmentExpression(node) {
const scope = sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9
if (
!isExports(node.left, scope) ||
// module.exports = exports = {}
(node.parent.type === "AssignmentExpression" &&
node.parent.right === node &&
isModuleExports(node.parent.left, scope)) ||
// exports = module.exports = {}
(node.right.type === "AssignmentExpression" &&
isModuleExports(node.right.left, scope))
) {
return
}
context.report({ node, messageId: "forbidden" })
},
}
},
}