diff --git a/src/reference-tracker.js b/src/reference-tracker.js index f63c2bd..ec5a193 100644 --- a/src/reference-tracker.js +++ b/src/reference-tracker.js @@ -2,7 +2,6 @@ import { findVariable } from "./find-variable" import { getPropertyName } from "./get-property-name" import { getStringIfConstant } from "./get-string-if-constant" -const SENTINEL_TYPE = /^(?:.+?Statement|.+?Declaration|(?:Array|ArrowFunction|Assignment|Call|Class|Function|Member|New|Object)Expression|AssignmentPattern|Program|VariableDeclarator)$/u const IMPORT_TYPE = /^(?:Import|Export(?:All|Default|Named))Declaration$/u const has = Function.call.bind(Object.hasOwnProperty) @@ -26,6 +25,28 @@ function isModifiedGlobal(variable) { ) } +/** + * Check if the value of a given node is passed through to the parent syntax as-is. + * For example, `a` and `b` in (`a || b` and `c ? a : b`) are passed through. + * @param {Node} node A node to check. + * @returns {boolean} `true` if the node is passed through. + */ +function isPassThrough(node) { + const parent = node.parent + + switch (parent && parent.type) { + case "ConditionalExpression": + return parent.consequent === node || parent.alternate === node + case "LogicalExpression": + return true + case "SequenceExpression": + return parent.expressions[parent.expressions.length - 1] === node + + default: + return false + } +} + /** * The reference tracker. */ @@ -227,7 +248,7 @@ export class ReferenceTracker { //eslint-disable-next-line complexity *_iteratePropertyReferences(rootNode, path, traceMap) { let node = rootNode - while (!SENTINEL_TYPE.test(node.parent.type)) { + while (isPassThrough(node)) { node = node.parent } diff --git a/test/reference-tracker.js b/test/reference-tracker.js index fc8b3ad..eb7166e 100644 --- a/test/reference-tracker.js +++ b/test/reference-tracker.js @@ -4,6 +4,7 @@ import { CALL, CONSTRUCT, ESM, READ, ReferenceTracker } from "../src/" const config = { parserOptions: { ecmaVersion: 2018, sourceType: "module" }, + globals: { Reflect: false }, rules: { test: "error" }, } @@ -369,6 +370,18 @@ describe("The 'ReferenceTracker' class:", () => { }, expected: [], }, + { + description: + "should not iterate the references through unary/binary expressions.", + code: [ + 'var construct = typeof Reflect !== "undefined" ? Reflect.construct : undefined', + "construct()", + ].join("\n"), + traceMap: { + Reflect: { [CALL]: 1 }, + }, + expected: [], + }, ]) { it(description, () => { const linter = new eslint.Linter()