44 */
55"use strict"
66
7- /**
8- * @typedef {import('estree').Node & { parent?: Node } } Node
9- */
7+ const { hasParentNode } = require ( "../util/has-parent-node.js" )
108
119/*istanbul ignore next */
1210/**
1311 * This function is copied from https://github.com/eslint/eslint/blob/2355f8d0de1d6732605420d15ddd4f1eee3c37b6/lib/ast-utils.js#L648-L684
1412 *
15- * @param {Node } node - The node to get.
13+ * @param {import('estree'). Node } node - The node to get.
1614 * @returns {string | null | undefined } The property name if static. Otherwise, null.
1715 * @private
1816 */
@@ -39,17 +37,12 @@ function getStaticPropertyName(node) {
3937
4038 case "TemplateLiteral" :
4139 if ( prop . expressions . length === 0 && prop . quasis . length === 1 ) {
42- return prop . quasis [ 0 ] . value . cooked
40+ return prop . quasis [ 0 ] ? .value . cooked
4341 }
4442 break
4543
4644 case "Identifier" :
47- if (
48- ! (
49- /** @type {import('estree').MemberExpression } */ ( node )
50- . computed
51- )
52- ) {
45+ if ( node . type === "MemberExpression" && node . computed === false ) {
5346 return prop . name
5447 }
5548 break
@@ -63,11 +56,12 @@ function getStaticPropertyName(node) {
6356/**
6457 * Checks whether the given node is assignee or not.
6558 *
66- * @param {Node } node - The node to check.
59+ * @param {import('estree'). Node } node - The node to check.
6760 * @returns {boolean } `true` if the node is assignee.
6861 */
6962function isAssignee ( node ) {
7063 return (
64+ hasParentNode ( node ) &&
7165 node . parent ?. type === "AssignmentExpression" &&
7266 node . parent . left === node
7367 )
@@ -79,15 +73,16 @@ function isAssignee(node) {
7973 * This is used to distinguish 2 assignees belong to the same assignment.
8074 * If the node is not an assignee, this returns null.
8175 *
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.
8478 */
8579function getTopAssignment ( leafNode ) {
8680 let node = leafNode
8781
8882 // Skip MemberExpressions.
8983 while (
90- node . parent ?. type === "MemberExpression" &&
84+ hasParentNode ( node ) &&
85+ node . parent . type === "MemberExpression" &&
9186 node . parent . object === node
9287 ) {
9388 node = node . parent
@@ -99,7 +94,7 @@ function getTopAssignment(leafNode) {
9994 }
10095
10196 // Find the top.
102- while ( node . parent ? .type === "AssignmentExpression" ) {
97+ while ( hasParentNode ( node ) && node . parent . type === "AssignmentExpression" ) {
10398 node = node . parent
10499 }
105100
@@ -109,35 +104,41 @@ function getTopAssignment(leafNode) {
109104/**
110105 * Gets top assignment nodes of the given node list.
111106 *
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.
114109 */
115110function createAssignmentList ( nodes ) {
116- return /** @type { Node[] } */ ( nodes . map ( getTopAssignment ) . filter ( Boolean ) )
111+ return nodes . map ( getTopAssignment ) . filter ( input => input != null )
117112}
118113
119114/**
120115 * Gets the reference of `module.exports` from the given scope.
121116 *
122117 * @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.
124119 */
125120function getModuleExportsNodes ( scope ) {
126121 const variable = scope . set . get ( "module" )
127122 if ( variable == null ) {
128123 return [ ]
129124 }
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
141142}
142143
143144/**
@@ -156,7 +157,7 @@ function getExportsNodes(scope) {
156157}
157158
158159/**
159- * @param {Node } property
160+ * @param {import('estree'). Node } property
160161 * @param {import('eslint').SourceCode } sourceCode
161162 * @returns {string | null }
162163 */
@@ -210,31 +211,36 @@ function getReplacementForProperty(property, sourceCode) {
210211
211212/**
212213 * Check for a top level module.exports = { ... }
213- * @param {Node } node
214+ * @param {import('estree'). Node } node
214215 * @returns {node is {parent: import('estree').AssignmentExpression & {parent: import('estree').ExpressionStatement, right: import('estree').ObjectExpression}} }
215216 */
216217function isModuleExportsObjectAssignment ( node ) {
217218 return (
219+ hasParentNode ( node ) &&
218220 node . parent ?. type === "AssignmentExpression" &&
221+ hasParentNode ( node . parent ) &&
219222 node . parent ?. parent ?. type === "ExpressionStatement" &&
223+ hasParentNode ( node . parent . parent ) &&
220224 node . parent . parent . parent ?. type === "Program" &&
221225 node . parent . right . type === "ObjectExpression"
222226 )
223227}
224228
225229/**
226230 * Check for module.exports.foo or module.exports.bar reference or assignment
227- * @param {Node } node
231+ * @param {import('estree'). Node } node
228232 * @returns {node is import('estree').MemberExpression }
229233 */
230234function isModuleExportsReference ( node ) {
231235 return (
232- node . parent ?. type === "MemberExpression" && node . parent . object === node
236+ hasParentNode ( node ) &&
237+ node . parent ?. type === "MemberExpression" &&
238+ node . parent . object === node
233239 )
234240}
235241
236242/**
237- * @param {Node } node
243+ * @param {import('estree'). Node } node
238244 * @param {import('eslint').SourceCode } sourceCode
239245 * @param {import('eslint').Rule.RuleFixer } fixer
240246 * @returns {import('eslint').Rule.Fix | null }
@@ -307,16 +313,17 @@ module.exports = {
307313 * module.exports = foo
308314 * ^^^^^^^^^^^^^^^^
309315 *
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.
312318 */
313319 function getLocation ( node ) {
314320 const token = sourceCode . getTokenAfter ( node )
321+ if ( node . loc ?. start == null || token ?. loc ?. end == null ) {
322+ return
323+ }
315324 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 ,
320327 }
321328 }
322329
0 commit comments