4
4
*/
5
5
"use strict"
6
6
7
- /**
8
- * @typedef {import('estree').Node & { parent?: Node } } Node
9
- */
7
+ const { hasParentNode } = require ( "../util/has-parent-node.js" )
10
8
11
9
/*istanbul ignore next */
12
10
/**
13
11
* This function is copied from https://github.com/eslint/eslint/blob/2355f8d0de1d6732605420d15ddd4f1eee3c37b6/lib/ast-utils.js#L648-L684
14
12
*
15
- * @param {Node } node - The node to get.
13
+ * @param {import('estree'). Node } node - The node to get.
16
14
* @returns {string | null | undefined } The property name if static. Otherwise, null.
17
15
* @private
18
16
*/
@@ -39,17 +37,12 @@ function getStaticPropertyName(node) {
39
37
40
38
case "TemplateLiteral" :
41
39
if ( prop . expressions . length === 0 && prop . quasis . length === 1 ) {
42
- return prop . quasis [ 0 ] . value . cooked
40
+ return prop . quasis [ 0 ] ? .value . cooked
43
41
}
44
42
break
45
43
46
44
case "Identifier" :
47
- if (
48
- ! (
49
- /** @type {import('estree').MemberExpression } */ ( node )
50
- . computed
51
- )
52
- ) {
45
+ if ( node . type === "MemberExpression" && node . computed === false ) {
53
46
return prop . name
54
47
}
55
48
break
@@ -63,11 +56,12 @@ function getStaticPropertyName(node) {
63
56
/**
64
57
* Checks whether the given node is assignee or not.
65
58
*
66
- * @param {Node } node - The node to check.
59
+ * @param {import('estree'). Node } node - The node to check.
67
60
* @returns {boolean } `true` if the node is assignee.
68
61
*/
69
62
function isAssignee ( node ) {
70
63
return (
64
+ hasParentNode ( node ) &&
71
65
node . parent ?. type === "AssignmentExpression" &&
72
66
node . parent . left === node
73
67
)
@@ -79,15 +73,16 @@ function isAssignee(node) {
79
73
* This is used to distinguish 2 assignees belong to the same assignment.
80
74
* If the node is not an assignee, this returns null.
81
75
*
82
- * @param {Node } leafNode - The node to get.
83
- * @returns {Node| null } The top assignment expression node, or null.
76
+ * @param {import('estree'). Node } leafNode - The node to get.
77
+ * @returns {import('estree'). Node | null } The top assignment expression node, or null.
84
78
*/
85
79
function getTopAssignment ( leafNode ) {
86
80
let node = leafNode
87
81
88
82
// Skip MemberExpressions.
89
83
while (
90
- node . parent ?. type === "MemberExpression" &&
84
+ hasParentNode ( node ) &&
85
+ node . parent . type === "MemberExpression" &&
91
86
node . parent . object === node
92
87
) {
93
88
node = node . parent
@@ -99,7 +94,7 @@ function getTopAssignment(leafNode) {
99
94
}
100
95
101
96
// Find the top.
102
- while ( node . parent ? .type === "AssignmentExpression" ) {
97
+ while ( hasParentNode ( node ) && node . parent . type === "AssignmentExpression" ) {
103
98
node = node . parent
104
99
}
105
100
@@ -109,35 +104,41 @@ function getTopAssignment(leafNode) {
109
104
/**
110
105
* Gets top assignment nodes of the given node list.
111
106
*
112
- * @param {Node[] } nodes - The node list to get.
113
- * @returns {Node[] } Gotten top assignment nodes.
107
+ * @param {import('estree'). Node[] } nodes - The node list to get.
108
+ * @returns {import('estree'). Node[] } Gotten top assignment nodes.
114
109
*/
115
110
function createAssignmentList ( nodes ) {
116
- return /** @type { Node[] } */ ( nodes . map ( getTopAssignment ) . filter ( Boolean ) )
111
+ return nodes . map ( getTopAssignment ) . filter ( input => input != null )
117
112
}
118
113
119
114
/**
120
115
* Gets the reference of `module.exports` from the given scope.
121
116
*
122
117
* @param {import('eslint').Scope.Scope } scope - The scope to get.
123
- * @returns {Node[] } Gotten MemberExpression node list.
118
+ * @returns {import('estree'). Node[] } Gotten MemberExpression node list.
124
119
*/
125
120
function getModuleExportsNodes ( scope ) {
126
121
const variable = scope . set . get ( "module" )
127
122
if ( variable == null ) {
128
123
return [ ]
129
124
}
130
- return variable . references
131
- . map (
132
- reference =>
133
- /** @type {Node & { parent: Node } } */ ( reference . identifier )
134
- . parent
135
- )
136
- . filter (
137
- node =>
138
- node ?. type === "MemberExpression" &&
139
- getStaticPropertyName ( node ) === "exports"
140
- )
125
+
126
+ /** @type {import('estree').Node[] } */
127
+ const nodes = [ ]
128
+
129
+ for ( const reference of variable . references ) {
130
+ if ( hasParentNode ( reference . identifier ) === false ) {
131
+ continue
132
+ }
133
+ const node = reference . identifier . parent
134
+ if (
135
+ node . type === "MemberExpression" &&
136
+ getStaticPropertyName ( node ) === "exports"
137
+ ) {
138
+ nodes . push ( node )
139
+ }
140
+ }
141
+ return nodes
141
142
}
142
143
143
144
/**
@@ -156,7 +157,7 @@ function getExportsNodes(scope) {
156
157
}
157
158
158
159
/**
159
- * @param {Node } property
160
+ * @param {import('estree'). Node } property
160
161
* @param {import('eslint').SourceCode } sourceCode
161
162
* @returns {string | null }
162
163
*/
@@ -210,31 +211,36 @@ function getReplacementForProperty(property, sourceCode) {
210
211
211
212
/**
212
213
* Check for a top level module.exports = { ... }
213
- * @param {Node } node
214
+ * @param {import('estree'). Node } node
214
215
* @returns {node is {parent: import('estree').AssignmentExpression & {parent: import('estree').ExpressionStatement, right: import('estree').ObjectExpression}} }
215
216
*/
216
217
function isModuleExportsObjectAssignment ( node ) {
217
218
return (
219
+ hasParentNode ( node ) &&
218
220
node . parent ?. type === "AssignmentExpression" &&
221
+ hasParentNode ( node . parent ) &&
219
222
node . parent ?. parent ?. type === "ExpressionStatement" &&
223
+ hasParentNode ( node . parent . parent ) &&
220
224
node . parent . parent . parent ?. type === "Program" &&
221
225
node . parent . right . type === "ObjectExpression"
222
226
)
223
227
}
224
228
225
229
/**
226
230
* Check for module.exports.foo or module.exports.bar reference or assignment
227
- * @param {Node } node
231
+ * @param {import('estree'). Node } node
228
232
* @returns {node is import('estree').MemberExpression }
229
233
*/
230
234
function isModuleExportsReference ( node ) {
231
235
return (
232
- node . parent ?. type === "MemberExpression" && node . parent . object === node
236
+ hasParentNode ( node ) &&
237
+ node . parent ?. type === "MemberExpression" &&
238
+ node . parent . object === node
233
239
)
234
240
}
235
241
236
242
/**
237
- * @param {Node } node
243
+ * @param {import('estree'). Node } node
238
244
* @param {import('eslint').SourceCode } sourceCode
239
245
* @param {import('eslint').Rule.RuleFixer } fixer
240
246
* @returns {import('eslint').Rule.Fix | null }
@@ -307,16 +313,17 @@ module.exports = {
307
313
* module.exports = foo
308
314
* ^^^^^^^^^^^^^^^^
309
315
*
310
- * @param {Node } node - The node of `exports`/`module.exports`.
311
- * @returns {import('estree').SourceLocation } The location info of reports.
316
+ * @param {import('estree'). Node } node - The node of `exports`/`module.exports`.
317
+ * @returns {import('estree').SourceLocation | undefined } The location info of reports.
312
318
*/
313
319
function getLocation ( node ) {
314
320
const token = sourceCode . getTokenAfter ( node )
321
+ if ( node . loc ?. start == null || token ?. loc ?. end == null ) {
322
+ return
323
+ }
315
324
return {
316
- start : /** @type {import('estree').SourceLocation } */ ( node . loc )
317
- . start ,
318
- end : /** @type {import('estree').SourceLocation } */ ( token ?. loc )
319
- ?. end ,
325
+ start : node . loc ?. start ,
326
+ end : token ?. loc ?. end ,
320
327
}
321
328
}
322
329
0 commit comments