diff --git a/eslint-plugin-expensify/CONST.js b/eslint-plugin-expensify/CONST.js index 966d318..1e69e06 100644 --- a/eslint-plugin-expensify/CONST.js +++ b/eslint-plugin-expensify/CONST.js @@ -28,5 +28,7 @@ module.exports = { MUST_USE_VARIABLE_FOR_ASSIGNMENT: '{{key}} must be assigned as a variable instead of direct assignment.', 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().', + PREFER_AT: 'Use the .at() method for array element access', }, }; diff --git a/eslint-plugin-expensify/prefer-at.js b/eslint-plugin-expensify/prefer-at.js new file mode 100644 index 0000000..15520a2 --- /dev/null +++ b/eslint-plugin-expensify/prefer-at.js @@ -0,0 +1,26 @@ +const message = require('./CONST').MESSAGE.PREFER_AT; + +module.exports = { + meta: { + fixable: 'code', + }, + + create(context) { + return { + MemberExpression(node) { + // Check if we are accessing an array element directly + if (node.object.type === 'Identifier' && node.property.type === 'Literal' && typeof node.property.value === 'number') { + context.report({ + node, + message, + fix(fixer) { + const arrayName = node.object.name; + const indexValue = node.property.value; + return fixer.replaceText(node, `${arrayName}.at(${indexValue})`); + }, + }); + } + }, + }; + }, +}; diff --git a/eslint-plugin-expensify/tests/prefer-at.test.js b/eslint-plugin-expensify/tests/prefer-at.test.js new file mode 100644 index 0000000..0ca02ed --- /dev/null +++ b/eslint-plugin-expensify/tests/prefer-at.test.js @@ -0,0 +1,37 @@ +const RuleTester = require('eslint').RuleTester; +const rule = require('../prefer-at'); +const message = require('../CONST').MESSAGE.PREFER_AT; + +const ruleTester = new RuleTester({ + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + }, +}); + +ruleTester.run('prefer-at', rule, { + valid: [ + { + code: 'example.at(0)', + }, + { + code: 'test.at(1)', + }, + ], + invalid: [ + { + code: 'example[0]', + output: 'example.at(0)', + errors: [{ + message, + }], + }, + { + code: 'test[1]', + output: 'test.at(1)', + errors: [{ + message, + }], + }, + ], +}); diff --git a/rules/expensify.js b/rules/expensify.js index fb5fccd..db48dcc 100644 --- a/rules/expensify.js +++ b/rules/expensify.js @@ -15,6 +15,8 @@ module.exports = { 'rulesdir/no-call-actions-from-actions': 'error', 'rulesdir/no-api-side-effects-method': 'error', 'rulesdir/prefer-localization': 'error', + 'rulesdir/use-double-negation-instead-of-boolean': 'error', + 'rulesdir/prefer-at': 'error', 'no-restricted-imports': ['error', { paths: [{ name: 'react-native', @@ -27,4 +29,4 @@ module.exports = { }], }], }, -}; \ No newline at end of file +};