From d540ae2bc853809298833d15accc892bb899ec38 Mon Sep 17 00:00:00 2001 From: hanli Date: Tue, 3 May 2022 22:26:12 -0700 Subject: [PATCH 1/3] Support `replace` in no-array-prototype-extensions --- lib/rules/no-array-prototype-extensions.js | 11 ++++++++++- tests/lib/rules/no-array-prototype-extensions.js | 10 +++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/rules/no-array-prototype-extensions.js b/lib/rules/no-array-prototype-extensions.js index d830c4aaca..53a2d3be62 100644 --- a/lib/rules/no-array-prototype-extensions.js +++ b/lib/rules/no-array-prototype-extensions.js @@ -28,7 +28,7 @@ const EXTENSION_METHODS = new Set([ 'without', /** * https://api.emberjs.com/ember/release/classes/MutableArray - * MutableArray methods excluding `replace` since it's part of string native functions + * MutableArray methods excluding `replace`. `replace` is handled differently as it's also part of String.prototype. * */ 'addObject', 'addObjects', @@ -47,6 +47,8 @@ const EXTENSION_METHODS = new Set([ 'unshiftObjects', ]); +const REPLACE_METHOD = 'replace'; + /** * https://api.emberjs.com/ember/release/classes/EmberArray * EmberArray properties excluding native props: [], length. @@ -98,6 +100,13 @@ module.exports = { if (EXTENSION_METHODS.has(node.callee.property.name)) { context.report({ node, messageId: 'main' }); } + + // Example: someArray.replace(1, 2, [1, 2, 3]); + // We can differentiate String.prototype.replace and Array.prototype.replace by arguments length + // String.prototype.replace can only have 2 arguments, Array.prototype.replace needs to have exact 3 arguments + if (node.callee.property.name === REPLACE_METHOD && node.arguments.length === 3) { + context.report({ node, messageId: 'main' }); + } }, /** diff --git a/tests/lib/rules/no-array-prototype-extensions.js b/tests/lib/rules/no-array-prototype-extensions.js index c703051e8c..4443f43ca8 100644 --- a/tests/lib/rules/no-array-prototype-extensions.js +++ b/tests/lib/rules/no-array-prototype-extensions.js @@ -36,9 +36,8 @@ ruleTester.run('no-array-prototype-extensions', rule, { /** Optional chaining */ 'arr?.notfirstObject?.foo', 'arr?.filter?.()', - /** Replace is part of string native prototypes */ - "'something'.replace()", - 'something.replace()', + /** String prototype replace */ + "'something'.replace(regexp, 'substring')", ], invalid: [ { @@ -272,5 +271,10 @@ ruleTester.run('no-array-prototype-extensions', rule, { output: null, errors: [{ messageId: 'main', type: 'CallExpression' }], }, + { + code: 'something.replace(1, 2, someArray)', + output: null, + errors: [{ messageId: 'main', type: 'CallExpression' }], + }, ], }); From 3f04ee1fe2ae88cf59b5592acb9dae1831e06a1f Mon Sep 17 00:00:00 2001 From: hanli Date: Tue, 3 May 2022 22:33:22 -0700 Subject: [PATCH 2/3] add another test, tweak wording --- tests/lib/rules/no-array-prototype-extensions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/lib/rules/no-array-prototype-extensions.js b/tests/lib/rules/no-array-prototype-extensions.js index 4443f43ca8..96eed47358 100644 --- a/tests/lib/rules/no-array-prototype-extensions.js +++ b/tests/lib/rules/no-array-prototype-extensions.js @@ -36,8 +36,9 @@ ruleTester.run('no-array-prototype-extensions', rule, { /** Optional chaining */ 'arr?.notfirstObject?.foo', 'arr?.filter?.()', - /** String prototype replace */ + /** String.prototype.replace() */ "'something'.replace(regexp, 'substring')", + "something.replace(regexp, 'substring')", ], invalid: [ { From ce70986c3a154ad2bf4f3f2deff4ce2379faccc5 Mon Sep 17 00:00:00 2001 From: hanli Date: Wed, 4 May 2022 10:50:00 -0700 Subject: [PATCH 3/3] Add more tests --- tests/lib/rules/no-array-prototype-extensions.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/lib/rules/no-array-prototype-extensions.js b/tests/lib/rules/no-array-prototype-extensions.js index 96eed47358..2f00d9b418 100644 --- a/tests/lib/rules/no-array-prototype-extensions.js +++ b/tests/lib/rules/no-array-prototype-extensions.js @@ -33,6 +33,9 @@ ruleTester.run('no-array-prototype-extensions', rule, { 'something[something.length - 1]', 'something.isAny', "something['compact']", + 'replace()', + 'replace(foo)', + 'replace(foo, bar, baz)', /** Optional chaining */ 'arr?.notfirstObject?.foo', 'arr?.filter?.()',