Skip to content

Commit

Permalink
Merge branch 'main' into boolean-update
Browse files Browse the repository at this point in the history
  • Loading branch information
ShridharGoel authored May 29, 2024
2 parents 2964450 + bc908fd commit 30a3dbf
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 3 deletions.
1 change: 1 addition & 0 deletions eslint-plugin-expensify/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ module.exports = {
NO_DEFAULT_PROPS: 'defaultProps should not be used in function components. Use default Arguments instead.',
USE_PERIODS_ERROR_MESSAGES: 'Use periods at the end of error messages.',
USE_DOUBLE_NEGATION_INSTEAD_OF_BOOLEAN: 'Use !! instead of Boolean().',
NO_ACC_SPREAD_IN_REDUCE: 'Avoid a use of spread (`...`) operator on accumulators in reduce callback. Mutate them directly instead.',
},
};
48 changes: 48 additions & 0 deletions eslint-plugin-expensify/no-acc-spread-in-reduce.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const _ = require('lodash');
const CONST = require('./CONST');

// Matches function expression as a direct descendant (argument callback) of "reduce" or "reduceRight" call
const MATCH = 'CallExpression:matches([callee.property.name="reduce"], [callee.property.name="reduceRight"]) > :matches(ArrowFunctionExpression, FunctionExpression)';

module.exports = {
meta: {
type: 'problem',
docs: {
description: CONST.MESSAGE.NO_ACC_SPREAD_IN_REDUCE,
category: 'Best Practices',
recommended: false,
},
schema: [], // no options
},
create(context) {
return {
[MATCH](node) {
// Retrieve accumulator variable
const accumulator = context.getDeclaredVariables(node)[0];
if (!accumulator) {
return;
}

// Check if accumulatorVariable has any references (is used in the scope)
if (!accumulator.references.length) {
return;
}

// Check if any of the references are used in a SpreadElement
const isAccumulatorVariableUsedSpread = _.some(
accumulator.references,
reference => reference.identifier.parent.type === 'SpreadElement',
);
if (!isAccumulatorVariableUsedSpread) {
return;
}

// Accumulator variable is used in a SpreadElement, report it
context.report({
node,
message: CONST.MESSAGE.NO_ACC_SPREAD_IN_REDUCE,
});
},
};
},
};
60 changes: 60 additions & 0 deletions eslint-plugin-expensify/tests/no-acc-spread-in-reduce.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const RuleTester = require('eslint').RuleTester;
const rule = require('../no-acc-spread-in-reduce');
const CONST = require('../CONST');

const ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
});

const errors = [
{
message: CONST.MESSAGE.NO_ACC_SPREAD_IN_REDUCE,
},
];

ruleTester.run('no-spread-in-reduce', rule, {
valid: [
{
code: `
array.reduce((acc, item) => {
acc[item.key] = item.value;
return acc;
}
, {});
`,
},
{
code: `
array.reduce((acc, item) => {
const spread = { ...somethingElse };
return acc[item.key] = item.value;
}, {});
`,
},
],
invalid: [
{
code: `
const arr = [];
arr.reduce((acc, i) => ({ ...acc, i }), {})
`,
errors,
},
{
code: `
const arr = [];
arr.reduceRight((acc, i) => ({ ...acc, i }), {})
`,
errors,
},
{
code: `
([]).reduce((acc, i) => ({ ...acc, i }), {})
`,
errors,
},
],
});
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-config-expensify",
"version": "2.0.48",
"version": "2.0.49",
"description": "Expensify's ESLint configuration following our style guide",
"main": "index.js",
"repository": {
Expand Down
1 change: 1 addition & 0 deletions rules/expensify.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module.exports = {
'rulesdir/no-api-side-effects-method': 'error',
'rulesdir/prefer-localization': 'error',
'rulesdir/use-double-negation-instead-of-boolean': 'error',
'rulesdir/no-acc-spread-in-reduce': 'error',
'no-restricted-imports': ['error', {
paths: [{
name: 'react-native',
Expand Down

0 comments on commit 30a3dbf

Please sign in to comment.