diff --git a/rules/prefer-array-find.js b/rules/prefer-array-find.js index 0f696f923c..c961fab858 100644 --- a/rules/prefer-array-find.js +++ b/rules/prefer-array-find.js @@ -87,17 +87,22 @@ const destructuringAssignmentSelector = [ // - `ObjectPattern`: `[{foo = baz}] = array.filter(bar)` const assignmentNeedParenthesize = ({type}) => type === 'ObjectExpression' || type === 'ObjectPattern'; -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Operator_precedence -// Higher than `??` and `||` -const hasHigherPrecedence = (node, operator) => ( +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table +const hasLowerPrecedence = (node, operator) => ( (node.type === 'LogicalExpression' && ( node.operator === operator || - // `??` has lower precedence than `||` - // https://tc39.es/proposal-nullish-coalescing/ - (operator === '??' && node.operator === '||') + // https://tc39.es/proposal-nullish-coalescing/ says + // `??` has lower precedence than `||` + // But MDN says + // `??` has higher precedence than `||` + (operator === '||' && node.operator === '??') || + (operator === '??' && (node.operator === '||' || node.operator === '&&')) )) || node.type === 'ConditionalExpression' || + // Lower than `assignment`, should already parenthesized + /* istanbul ignore next */ node.type === 'AssignmentExpression' || + node.type === 'YieldExpression' || node.type === 'SequenceExpression' ); @@ -128,7 +133,7 @@ const fixDestructuring = (source, node) => { const defaultValue = element.right; let defaultValueText = source.getText(defaultValue); - if (isParenthesized(defaultValue, source) || hasHigherPrecedence(defaultValue, operator)) { + if (isParenthesized(defaultValue, source) || hasLowerPrecedence(defaultValue, operator)) { defaultValueText = `(${defaultValueText})`; } diff --git a/test/prefer-array-find.js b/test/prefer-array-find.js index ef06267ec1..f46ba51071 100644 --- a/test/prefer-array-find.js +++ b/test/prefer-array-find.js @@ -312,6 +312,24 @@ ruleTester.run('prefer-array-find', rule, { ] }] }, + // // TODO: enable this test when ESLint support `nullish coalescing operator` + // { + // code: 'const [foo = a ?? b] = array.filter(bar)', + // output: 'const [foo = a ?? b] = array.filter(bar)', + // errors: [{ + // messageId: MESSAGE_ID_DESTRUCTURING_DECLARATION, + // suggestions: [ + // { + // messageId: MESSAGE_ID_USE_NULLISH_COALESCING_OPERATOR, + // output: 'const foo = array.find(bar) ?? (a ?? b)' + // }, + // { + // messageId: MESSAGE_ID_USE_LOGICAL_OR_OPERATOR, + // output: 'const foo = array.find(bar) || (a ?? b)' + // } + // ] + // }] + // }, { code: 'const [foo = a || b] = array.filter(bar)', output: 'const [foo = a || b] = array.filter(bar)', @@ -328,6 +346,23 @@ ruleTester.run('prefer-array-find', rule, { } ] }] + }, + { + code: 'const [foo = a && b] = array.filter(bar)', + output: 'const [foo = a && b] = array.filter(bar)', + errors: [{ + messageId: MESSAGE_ID_DESTRUCTURING_DECLARATION, + suggestions: [ + { + messageId: MESSAGE_ID_USE_NULLISH_COALESCING_OPERATOR, + output: 'const foo = array.find(bar) ?? (a && b)' + }, + { + messageId: MESSAGE_ID_USE_LOGICAL_OR_OPERATOR, + output: 'const foo = array.find(bar) || a && b' + } + ] + }] } ] });