diff --git a/configs/recommended.js b/configs/recommended.js index 1c83f44a2c..901dee7985 100644 --- a/configs/recommended.js +++ b/configs/recommended.js @@ -87,6 +87,7 @@ module.exports = { 'unicorn/prefer-modern-dom-apis': 'error', 'unicorn/prefer-modern-math-apis': 'error', 'unicorn/prefer-module': 'error', + 'unicorn/prefer-native-coercion-functions': 'error', 'unicorn/prefer-negative-index': 'error', 'unicorn/prefer-node-protocol': 'error', 'unicorn/prefer-number-properties': 'error', diff --git a/docs/rules/prefer-native-coercion-functions.md b/docs/rules/prefer-native-coercion-functions.md new file mode 100644 index 0000000000..7ba6aab7e4 --- /dev/null +++ b/docs/rules/prefer-native-coercion-functions.md @@ -0,0 +1,68 @@ +# Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly + + + +βœ… *This rule is part of the [recommended](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config) config.* + +πŸ”§ *This rule is [auto-fixable](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems).* + + +If a function is equivalent to [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt), [`Boolean`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean), or [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol), you should use the built-in one directly. Wrapping the built-in in a function is moot. + +## Fail + +```js +const toBoolean = value => Boolean(value); +``` + +```js +function toNumber(value) { + return Number(value); +} + +if (toNumber(foo) === 1) {} +``` + +```js +const hasTruthyValue = array.some(element => element); +``` + +## Pass + +```js +const toBoolean = Boolean; +``` + +```js +if (Number(foo) === 1) {} +``` + +```js +const hasTruthyValue = array.some(Boolean); +``` + +```js +const toStringObject = value => new String(value); +``` + +```js +const toObject= value => Object(value); +``` + +## Note + +We don't check implicit coercion like: + +```js +const toString = value => '' + value; +``` + +```js +const toNumber = value => +value; +``` + +```js +const toBoolean = value => !!value; +``` + +It is recommended to enable the built-in ESLint rule [`no-implicit-coercion`](https://eslint.org/docs/rules/no-implicit-coercion) for a better experience. diff --git a/readme.md b/readme.md index 2e6c45119b..c2f1f18f76 100644 --- a/readme.md +++ b/readme.md @@ -127,6 +127,7 @@ Each rule has emojis denoting: | [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | βœ… | πŸ”§ | | | [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | βœ… | πŸ”§ | | | [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | βœ… | πŸ”§ | | | [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` for `{String,Array,TypedArray}#slice()`, `Array#splice()` and `Array#at()`. | βœ… | πŸ”§ | | | [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | βœ… | πŸ”§ | | | [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | βœ… | πŸ”§ | πŸ’‘ | diff --git a/rules/prefer-native-coercion-functions.js b/rules/prefer-native-coercion-functions.js new file mode 100644 index 0000000000..2ad682c6ec --- /dev/null +++ b/rules/prefer-native-coercion-functions.js @@ -0,0 +1,182 @@ +'use strict'; +const {getFunctionHeadLocation, getFunctionNameWithKind} = require('eslint-utils'); +const {not} = require('./selectors/index.js'); + +const MESSAGE_ID = 'prefer-native-coercion-functions'; +const messages = { + [MESSAGE_ID]: '{{functionNameWithKind}} is equivalent to `{{replacementFunction}}`. Use `{{replacementFunction}}` directly.', +}; + +const nativeCoercionFunctionNames = new Set(['String', 'Number', 'BigInt', 'Boolean', 'Symbol']); +const arrayMethodsWithBooleanCallback = new Set(['every', 'filter', 'find', 'findIndex', 'some']); + +const isNativeCoercionFunctionCall = (node, firstArgumentName) => + node + && node.type === 'CallExpression' + && !node.optional + && node.callee.type === 'Identifier' + && nativeCoercionFunctionNames.has(node.callee.name) + && node.arguments[0] + && node.arguments[0].type === 'Identifier' + && node.arguments[0].name === firstArgumentName; + +const isIdentityFunction = node => + ( + // `v => v` + node.type === 'ArrowFunctionExpression' + && node.body.type === 'Identifier' + && node.body.name === node.params[0].name + ) + || ( + // `(v) => {return v;}` + // `function (v) {return v;}` + node.body.type === 'BlockStatement' + && node.body.body.length === 1 + && node.body.body[0].type === 'ReturnStatement' + && node.body.body[0].argument + && node.body.body[0].argument.type === 'Identifier' + && node.body.body[0].argument.name === node.params[0].name + ); + +const isArrayIdentityCallback = node => + isIdentityFunction(node) + && node.parent.type === 'CallExpression' + && !node.parent.optional + && node.parent.arguments[0] === node + && node.parent.callee.type === 'MemberExpression' + && !node.parent.callee.computed + && !node.parent.callee.optional + && node.parent.callee.property.type === 'Identifier' + && arrayMethodsWithBooleanCallback.has(node.parent.callee.property.name); + +function getCallExpression(node) { + const firstParameterName = node.params[0].name; + + // `(v) => String(v)` + if ( + node.type === 'ArrowFunctionExpression' + && isNativeCoercionFunctionCall(node.body, firstParameterName) + ) { + return node.body; + } + + // `(v) => {return String(v);}` + // `function (v) {return String(v);}` + if ( + node.body.type === 'BlockStatement' + && node.body.body.length === 1 + && node.body.body[0].type === 'ReturnStatement' + && isNativeCoercionFunctionCall(node.body.body[0].argument, firstParameterName) + ) { + return node.body.body[0].argument; + } +} + +const functionsSelector = [ + ':function', + '[async!=true]', + '[generator!=true]', + '[params.length>0]', + '[params.0.type="Identifier"]', + not([ + 'MethodDefinition[kind="constructor"] > .value', + 'MethodDefinition[kind="set"] > .value', + 'Property[kind="set"] > .value', + ]), +].join(''); + +function getArrayCallbackProblem(node) { + if (!isArrayIdentityCallback(node)) { + return; + } + + return { + replacementFunction: 'Boolean', + fix: fixer => fixer.replaceText(node, 'Boolean'), + }; +} + +function getCoercionFunctionProblem(node) { + const callExpression = getCallExpression(node); + + if (!callExpression) { + return; + } + + const {name} = callExpression.callee; + + const problem = {replacementFunction: name}; + + if (node.type === 'FunctionDeclaration' || callExpression.arguments.length !== 1) { + return problem; + } + + /** @param {import('eslint').Rule.RuleFixer} fixer */ + problem.fix = fixer => { + let text = name; + + if ( + node.parent.type === 'Property' + && node.parent.method + && node.parent.value === node + ) { + text = `: ${text}`; + } else if (node.parent.type === 'MethodDefinition') { + text = ` = ${text};`; + } + + return fixer.replaceText(node, text); + }; + + return problem; +} + +/** @param {import('eslint').Rule.RuleContext} context */ +const create = context => ({ + [functionsSelector](node) { + let problem = getArrayCallbackProblem(node) || getCoercionFunctionProblem(node); + + if (!problem) { + return; + } + + const sourceCode = context.getSourceCode(); + const {replacementFunction, fix} = problem; + + problem = { + node, + loc: getFunctionHeadLocation(node, sourceCode), + messageId: MESSAGE_ID, + data: { + functionNameWithKind: getFunctionNameWithKind(node, sourceCode), + replacementFunction, + }, + }; + + /* + We do not fix if there are: + - Comments: No proper place to put them. + - Extra parameters: Removing them may break types. + */ + if (!fix || node.params.length !== 1 || sourceCode.getCommentsInside(node).length > 0) { + return problem; + } + + problem.fix = fix; + + return problem; + }, +}); + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + create, + meta: { + type: 'suggestion', + docs: { + description: 'Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly.', + }, + fixable: 'code', + messages, + }, +}; diff --git a/test/prefer-native-coercion-functions.mjs b/test/prefer-native-coercion-functions.mjs new file mode 100644 index 0000000000..00aad04266 --- /dev/null +++ b/test/prefer-native-coercion-functions.mjs @@ -0,0 +1,206 @@ +import outdent from 'outdent'; +import {getTester} from './utils/test.mjs'; + +const {test} = getTester(import.meta); + +test.snapshot({ + valid: [ + 'const foo = async v => String(v)', + 'const foo = v => String', + 'const foo = v => v', + 'const foo = v => NotString(v)', + 'const foo = v => String(notFirstParameterName)', + 'const foo = v => new String(v)', + 'const foo = v => String?.(v)', + 'const foo = async function (v) {return String(v);}', + 'const foo = function * (v) {return String(v);}', + 'const foo = async function * (v) {return String(v);}', + 'const foo = function * (v) {yield String(v);}', + 'const foo = async function (v) {await String(v);}', + 'const foo = function (v) {return;}', + outdent` + function foo(v) { + 'use strict'; + return String(v); + } + `, + outdent` + function foo(v) { + return String(v); + function x() {} + } + `, + outdent` + function foo({v}) { + return String(v); + } + `, + outdent` + function foo(v) { + return String({v}); + } + `, + outdent` + function foo(...v) { + return String(v); + } + `, + outdent` + function foo(...v) { + return String(...v); + } + `, + outdent` + class A { + constructor(v) { + return String(v); + } + } + `, + outdent` + class A { + get foo() { + return String(v); + } + } + `, + outdent` + class A { + set foo(v) { + return String(v); + } + } + `, + '({get foo() {return String(v)}})', + '({set foo(v) {return String(v)}})', + ], + invalid: [ + 'const foo = v => String(v)', + 'const foo = v => Number(v)', + 'const foo = v => BigInt(v)', + 'const foo = v => Boolean(v)', + 'const foo = v => Symbol(v)', + outdent` + const foo = v => { + return String(v); + } + `, + outdent` + const foo = function (v) { + return String(v); + } + `, + 'function foo(v) { return String(v); }', + 'export default function foo(v) { return String(v); }', + 'export default function (v) { return String(v); }', + outdent` + class A { + foo(v) { + return String(v); + } + + bar() {} + } + `, + outdent` + class A { + static foo(v) { + return String(v); + } + + bar() {} + } + `, + outdent` + class A { + #foo(v) { + return String(v); + } + + bar() {} + } + `, + outdent` + class A { + static #foo(v) { + return String(v); + } + + bar() {} + } + `, + outdent` + object = { + foo(v) { + return String(v); + }, + bar + } + `, + outdent` + object = { + foo: function(v) { + return String(v); + }, + bar + } + `, + outdent` + object = { + [function(v) {return String(v);}]: 1, + } + `, + + // No fix + 'const foo = (v, extra) => String(v)', + 'const foo = (v, ) => String(v, extra)', + 'const foo = (v, ) => /* comment */ String(v)', + ], +}); + +// Array callbacks +test.snapshot({ + valid: [ + 'array.some?.(v => v)', + 'array?.some(v => v)', + 'array.notSome(v => v)', + 'array.some(callback, v => v)', + 'some(v => v)', + 'array.some(v => notFirstParameterName)', + 'array.some(function(v) {return notFirstParameterName;})', + 'array.some(function(v) {return;})', + 'array.some(function(v) {return v.v;})', + outdent` + const identity = v => v; + array.some(identity) + `, + outdent` + array.some(function(v) { + "use strict"; + return v; + }) + `, + ], + invalid: [ + 'array.every(v => v)', + 'array.filter(v => v)', + 'array.find(v => v)', + 'array.some(v => v)', + 'array.findIndex(v => v)', + 'array.some(v => v)', + outdent` + array.some(v => { + return v; + }) + `, + outdent` + array.some(function (v) { + return v; + }) + `, + + // No fix + 'array.some((v, extra) => v)', + 'array.some((v, ) => /* comment */ v)', + ], +}); diff --git a/test/snapshots/prefer-native-coercion-functions.mjs.md b/test/snapshots/prefer-native-coercion-functions.mjs.md new file mode 100644 index 0000000000..13f003c592 --- /dev/null +++ b/test/snapshots/prefer-native-coercion-functions.mjs.md @@ -0,0 +1,549 @@ +# Snapshot report for `test/prefer-native-coercion-functions.mjs` + +The actual snapshot is saved in `prefer-native-coercion-functions.mjs.snap`. + +Generated by [AVA](https://avajs.dev). + +## Invalid #1 + 1 | const foo = v => String(v) + +> Output + + `␊ + 1 | const foo = String␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = v => String(v)␊ + | ^^ arrow function 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + ` + +## Invalid #2 + 1 | const foo = v => Number(v) + +> Output + + `␊ + 1 | const foo = Number␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = v => Number(v)␊ + | ^^ arrow function 'foo' is equivalent to \`Number\`. Use \`Number\` directly.␊ + ` + +## Invalid #3 + 1 | const foo = v => BigInt(v) + +> Output + + `␊ + 1 | const foo = BigInt␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = v => BigInt(v)␊ + | ^^ arrow function 'foo' is equivalent to \`BigInt\`. Use \`BigInt\` directly.␊ + ` + +## Invalid #4 + 1 | const foo = v => Boolean(v) + +> Output + + `␊ + 1 | const foo = Boolean␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = v => Boolean(v)␊ + | ^^ arrow function 'foo' is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` + +## Invalid #5 + 1 | const foo = v => Symbol(v) + +> Output + + `␊ + 1 | const foo = Symbol␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = v => Symbol(v)␊ + | ^^ arrow function 'foo' is equivalent to \`Symbol\`. Use \`Symbol\` directly.␊ + ` + +## Invalid #6 + 1 | const foo = v => { + 2 | return String(v); + 3 | } + +> Output + + `␊ + 1 | const foo = String␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = v => {␊ + | ^^ arrow function 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + 2 | return String(v);␊ + 3 | }␊ + ` + +## Invalid #7 + 1 | const foo = function (v) { + 2 | return String(v); + 3 | } + +> Output + + `␊ + 1 | const foo = String␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = function (v) {␊ + | ^^^^^^^^^ function 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + 2 | return String(v);␊ + 3 | }␊ + ` + +## Invalid #8 + 1 | function foo(v) { return String(v); } + +> Error 1/1 + + `␊ + > 1 | function foo(v) { return String(v); }␊ + | ^^^^^^^^^^^^ function 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + ` + +## Invalid #9 + 1 | export default function foo(v) { return String(v); } + +> Error 1/1 + + `␊ + > 1 | export default function foo(v) { return String(v); }␊ + | ^^^^^^^^^^^^ function 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + ` + +## Invalid #10 + 1 | export default function (v) { return String(v); } + +> Error 1/1 + + `␊ + > 1 | export default function (v) { return String(v); }␊ + | ^^^^^^^^^ function is equivalent to \`String\`. Use \`String\` directly.␊ + ` + +## Invalid #11 + 1 | class A { + 2 | foo(v) { + 3 | return String(v); + 4 | } + 5 | + 6 | bar() {} + 7 | } + +> Output + + `␊ + 1 | class A {␊ + 2 | foo = String;␊ + 3 |␊ + 4 | bar() {}␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | class A {␊ + > 2 | foo(v) {␊ + | ^^^ method 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + 3 | return String(v);␊ + 4 | }␊ + 5 |␊ + 6 | bar() {}␊ + 7 | }␊ + ` + +## Invalid #12 + 1 | class A { + 2 | static foo(v) { + 3 | return String(v); + 4 | } + 5 | + 6 | bar() {} + 7 | } + +> Output + + `␊ + 1 | class A {␊ + 2 | static foo = String;␊ + 3 |␊ + 4 | bar() {}␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | class A {␊ + > 2 | static foo(v) {␊ + | ^^^^^^^^^^ static method 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + 3 | return String(v);␊ + 4 | }␊ + 5 |␊ + 6 | bar() {}␊ + 7 | }␊ + ` + +## Invalid #13 + 1 | class A { + 2 | #foo(v) { + 3 | return String(v); + 4 | } + 5 | + 6 | bar() {} + 7 | } + +> Output + + `␊ + 1 | class A {␊ + 2 | #foo = String;␊ + 3 |␊ + 4 | bar() {}␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | class A {␊ + > 2 | #foo(v) {␊ + | ^^^^ private method #foo is equivalent to \`String\`. Use \`String\` directly.␊ + 3 | return String(v);␊ + 4 | }␊ + 5 |␊ + 6 | bar() {}␊ + 7 | }␊ + ` + +## Invalid #14 + 1 | class A { + 2 | static #foo(v) { + 3 | return String(v); + 4 | } + 5 | + 6 | bar() {} + 7 | } + +> Output + + `␊ + 1 | class A {␊ + 2 | static #foo = String;␊ + 3 |␊ + 4 | bar() {}␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | class A {␊ + > 2 | static #foo(v) {␊ + | ^^^^^^^^^^^ static private method #foo is equivalent to \`String\`. Use \`String\` directly.␊ + 3 | return String(v);␊ + 4 | }␊ + 5 |␊ + 6 | bar() {}␊ + 7 | }␊ + ` + +## Invalid #15 + 1 | object = { + 2 | foo(v) { + 3 | return String(v); + 4 | }, + 5 | bar + 6 | } + +> Output + + `␊ + 1 | object = {␊ + 2 | foo: String,␊ + 3 | bar␊ + 4 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | object = {␊ + > 2 | foo(v) {␊ + | ^^^ method 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + 3 | return String(v);␊ + 4 | },␊ + 5 | bar␊ + 6 | }␊ + ` + +## Invalid #16 + 1 | object = { + 2 | foo: function(v) { + 3 | return String(v); + 4 | }, + 5 | bar + 6 | } + +> Output + + `␊ + 1 | object = {␊ + 2 | foo: String,␊ + 3 | bar␊ + 4 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | object = {␊ + > 2 | foo: function(v) {␊ + | ^^^^^^^^^^^^^ method 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + 3 | return String(v);␊ + 4 | },␊ + 5 | bar␊ + 6 | }␊ + ` + +## Invalid #17 + 1 | object = { + 2 | [function(v) {return String(v);}]: 1, + 3 | } + +> Output + + `␊ + 1 | object = {␊ + 2 | [String]: 1,␊ + 3 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | object = {␊ + > 2 | [function(v) {return String(v);}]: 1,␊ + | ^^^^^^^^^ function is equivalent to \`String\`. Use \`String\` directly.␊ + 3 | }␊ + ` + +## Invalid #18 + 1 | const foo = (v, extra) => String(v) + +> Error 1/1 + + `␊ + > 1 | const foo = (v, extra) => String(v)␊ + | ^^ arrow function 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + ` + +## Invalid #19 + 1 | const foo = (v, ) => String(v, extra) + +> Error 1/1 + + `␊ + > 1 | const foo = (v, ) => String(v, extra)␊ + | ^^ arrow function 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + ` + +## Invalid #20 + 1 | const foo = (v, ) => /* comment */ String(v) + +> Error 1/1 + + `␊ + > 1 | const foo = (v, ) => /* comment */ String(v)␊ + | ^^ arrow function 'foo' is equivalent to \`String\`. Use \`String\` directly.␊ + ` + +## Invalid #1 + 1 | array.every(v => v) + +> Output + + `␊ + 1 | array.every(Boolean)␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.every(v => v)␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` + +## Invalid #2 + 1 | array.filter(v => v) + +> Output + + `␊ + 1 | array.filter(Boolean)␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.filter(v => v)␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` + +## Invalid #3 + 1 | array.find(v => v) + +> Output + + `␊ + 1 | array.find(Boolean)␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.find(v => v)␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` + +## Invalid #4 + 1 | array.some(v => v) + +> Output + + `␊ + 1 | array.some(Boolean)␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.some(v => v)␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` + +## Invalid #5 + 1 | array.findIndex(v => v) + +> Output + + `␊ + 1 | array.findIndex(Boolean)␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.findIndex(v => v)␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` + +## Invalid #6 + 1 | array.some(v => v) + +> Output + + `␊ + 1 | array.some(Boolean)␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.some(v => v)␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` + +## Invalid #7 + 1 | array.some(v => { + 2 | return v; + 3 | }) + +> Output + + `␊ + 1 | array.some(Boolean)␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.some(v => {␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + 2 | return v;␊ + 3 | })␊ + ` + +## Invalid #8 + 1 | array.some(function (v) { + 2 | return v; + 3 | }) + +> Output + + `␊ + 1 | array.some(Boolean)␊ + ` + +> Error 1/1 + + `␊ + > 1 | array.some(function (v) {␊ + | ^^^^^^^^^ function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + 2 | return v;␊ + 3 | })␊ + ` + +## Invalid #9 + 1 | array.some((v, extra) => v) + +> Error 1/1 + + `␊ + > 1 | array.some((v, extra) => v)␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` + +## Invalid #10 + 1 | array.some((v, ) => /* comment */ v) + +> Error 1/1 + + `␊ + > 1 | array.some((v, ) => /* comment */ v)␊ + | ^^ arrow function is equivalent to \`Boolean\`. Use \`Boolean\` directly.␊ + ` diff --git a/test/snapshots/prefer-native-coercion-functions.mjs.snap b/test/snapshots/prefer-native-coercion-functions.mjs.snap new file mode 100644 index 0000000000..ced26e1d94 Binary files /dev/null and b/test/snapshots/prefer-native-coercion-functions.mjs.snap differ