Skip to content

Commit

Permalink
fix: false positive with deferred/promise.reject() in no-array-protot…
Browse files Browse the repository at this point in the history
…ype-extensions (#1552)
  • Loading branch information
bmish authored Aug 2, 2022
1 parent da46812 commit 4c5c086
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
30 changes: 19 additions & 11 deletions lib/rules/no-array-prototype-extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,14 @@ const KNOWN_NON_ARRAY_CLASSES = new Set([
]);

/**
* Ignore variables containing these words as they are likely to be instances of non-array classes.
* Stored in lowercase.
* Ignore certain function calls made on variables containing certain words as they are likely to be instances of non-array classes.
* Words stored in lowercase.
*/
const KNOWN_NON_ARRAY_WORDS_WITH_CLEAR_FN = new Set([
const FN_NAMES_TO_KNOWN_NON_ARRAY_WORDS = new Map([
// These Promise-related objects have an overlapping reject() method.
['reject', new Set(['deferred', 'promise'])],
// These Set/Map data structure classes have an overlapping clear() method.
'set',
'map',
['clear', new Set(['set', 'map'])],
]);

/**
Expand Down Expand Up @@ -198,16 +199,23 @@ module.exports = {
const nameParts = name.split('.');
if (
KNOWN_NON_ARRAY_FUNCTION_CALLS.has(name) ||
KNOWN_NON_ARRAY_OBJECTS.has(nameParts[nameParts.length - 2]) ||
(variableNameToWords(nameParts[nameParts.length - 2]).some((word) =>
KNOWN_NON_ARRAY_WORDS_WITH_CLEAR_FN.has(word)
) &&
nameParts[nameParts.length - 1] === 'clear()')
KNOWN_NON_ARRAY_OBJECTS.has(nameParts[nameParts.length - 2])
) {
// Ignore any known non-array objects/function calls/variable names to reduce false positives.
// Ignore any known non-array objects/function calls to reduce false positives.
return;
}

for (const functionName of FN_NAMES_TO_KNOWN_NON_ARRAY_WORDS.keys()) {
const words = FN_NAMES_TO_KNOWN_NON_ARRAY_WORDS.get(functionName);
if (
nameParts[nameParts.length - 1] === `${functionName}()` &&
variableNameToWords(nameParts[nameParts.length - 2]).some((word) => words.has(word))
) {
// We found a function call on a variable whose name contains a word that indicates this variable is not an array.
return;
}
}

const nodeInitializedTo = getNodeOrNodeFromVariable(node.callee.object, scopeManager);
if (
nodeInitializedTo.type === 'NewExpression' &&
Expand Down
18 changes: 18 additions & 0 deletions tests/lib/rules/no-array-prototype-extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ ruleTester.run('no-array-prototype-extensions', rule, {
'Ember.RSVP.reject();',
'Ember.RSVP.Promise.reject();',

// `reject()` on instance of `RSVP.defer`.
`
import { defer } from 'rsvp';
const deferred = defer();
deferred.reject();`,
`
import { defer } from 'rsvp';
const requestDeferred = defer();
requestDeferred.reject();`,
`
import { defer } from 'rsvp';
const promise = defer();
promise.reject();`,
`
import { defer } from 'rsvp';
const fooPromise = defer();
fooPromise.reject();`,

// Global non-array class (*storage.clear)
'window.localStorage.clear();',
'window.sessionStorage.clear();',
Expand Down

0 comments on commit 4c5c086

Please sign in to comment.