Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(eslint-plugin): [strict-boolean-expressions] check array predicate functions' return statements#10106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
45 commits
Select commitHold shift + click to select a range
95525e0
initial implementation
ronamiOct 4, 2024
e6dd55c
tests
ronamiOct 4, 2024
1a898fe
refactor
ronamiOct 5, 2024
a16f46e
some more tests
ronamiOct 5, 2024
057a68e
update docs
ronamiOct 5, 2024
d2ea1ab
update snapshots
ronamiOct 5, 2024
116c80b
merge conflicts
ronamiOct 11, 2024
d641dc9
handle implicit or explicit undefined return types
ronamiOct 11, 2024
8d997d1
refactor and update tests
ronamiOct 11, 2024
47c167c
remove unnecessary union check
ronamiOct 11, 2024
90f9ba8
inline check
ronamiOct 11, 2024
42a1336
cover empty return staetments
ronamiOct 11, 2024
655e52c
report a function as returning undefined only if no other isssues wer…
ronamiOct 11, 2024
b8643c9
update comments
ronamiOct 11, 2024
c665d82
add test
ronamiOct 11, 2024
b3dd8be
remove unnecessary test
ronamiOct 11, 2024
fc0ea08
Merge branch 'main' into strict-boolean-expressions-predicates
ronamiNov 2, 2024
5691380
update code to match function's inferred return type rather than each…
ronamiOct 30, 2024
f718885
update tests to match the implementation changes
ronamiNov 2, 2024
dbc4c7a
adjust suggestion message
ronamiNov 2, 2024
f6329dc
final adjustments
ronamiNov 2, 2024
3ce22c5
final adjustments #2
ronamiNov 2, 2024
96ef5c0
test additions
ronamiNov 2, 2024
403c011
update snapshots
ronamiNov 2, 2024
339fa3a
Update packages/eslint-plugin/docs/rules/strict-boolean-expressions.mdx
ronamiNov 11, 2024
30b3d1c
initial implementation of deducing the correct signature for non-func…
ronamiNov 27, 2024
690fdbc
comments
ronamiNov 27, 2024
d607a00
take type constraints into consideration
ronamiNov 27, 2024
f5c7300
only check type constraints on type parameters
ronamiNov 27, 2024
287122e
update tests
ronamiNov 27, 2024
7566d0b
update index tests
ronamiNov 27, 2024
d472c86
update snapshot
ronamiNov 27, 2024
00b8424
simplify code a bit
ronamiNov 28, 2024
5e59733
remove overly complex heuristic
ronamiDec 17, 2024
d2a254a
use an existing helper rather than implementing one
ronamiDec 17, 2024
6b32e50
update tests
ronamiDec 17, 2024
c97d53c
Update packages/eslint-plugin/src/rules/strict-boolean-expressions.ts
ronamiDec 17, 2024
ac6be7e
fix codecov
ronamiDec 17, 2024
e94c0ee
cleanup old code, support type constraints
ronamiDec 19, 2024
601dfba
refactor fixer
ronamiDec 19, 2024
1994ba6
remove unnecessary tests
ronamiDec 19, 2024
c71112b
Merge branch 'main' into strict-boolean-expressions-predicates
ronamiDec 19, 2024
8e54722
revert changes to isParenlessArrowFunction
ronamiDec 26, 2024
abfb9f7
Merge branch 'main' into strict-boolean-expressions-predicates
ronamiDec 26, 2024
f17a05c
oops
ronamiDec 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ The following nodes are considered boolean expressions and their type is checked
- Right-hand side operand is ignored when it's not a descendant of another boolean expression.
This is to allow usage of boolean operators for their short-circuiting behavior.
- Asserted argument of an assertion function (`assert(arg)`).
- Return type of array predicate functions such as `filter()`, `some()`, etc.

## Examples

Expand DownExpand Up@@ -61,6 +62,9 @@ while (obj) {
declare function assert(value: unknown): asserts value;
let maybeString = Math.random() > 0.5 ? '' : undefined;
assert(maybeString);

// array predicates' return types are boolean contexts.
['one', null].filter(x => x);
```

</TabItem>
Expand Down
127 changes: 119 additions & 8 deletionspackages/eslint-plugin/src/rules/strict-boolean-expressions.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import type {
TSESTree,
} from '@typescript-eslint/utils';

import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils';
import * as tsutils from 'ts-api-utils';
import * as ts from 'typescript';

Expand All@@ -12,7 +12,10 @@ import {
getConstrainedTypeAtLocation,
getParserServices,
getWrappingFixer,
isArrayMethodCallWithPredicate,
isParenlessArrowFunction,
isTypeArrayTypeOrUnionOfArrayTypes,
nullThrows,
} from '../util';
import { findTruthinessAssertedArgument } from '../util/assertionFunctionUtils';

Expand DownExpand Up@@ -53,7 +56,10 @@ export type MessageId =
| 'conditionFixDefaultEmptyString'
| 'conditionFixDefaultFalse'
| 'conditionFixDefaultZero'
| 'noStrictNullCheck';
| 'explicitBooleanReturnType'
| 'noStrictNullCheck'
| 'predicateCannotBeAsync'
| 'predicateReturnsNonBoolean';

export default createRule<Options, MessageId>({
name: 'strict-boolean-expressions',
Expand DownExpand Up@@ -122,8 +128,13 @@ export default createRule<Options, MessageId>({
'Explicitly treat nullish value the same as false (`value ?? false`)',
conditionFixDefaultZero:
'Explicitly treat nullish value the same as 0 (`value ?? 0`)',
explicitBooleanReturnType:
'Add an explicit `boolean` return type annotation.',
noStrictNullCheck:
'This rule requires the `strictNullChecks` compiler option to be turned on to function correctly.',
predicateCannotBeAsync:
"Predicate function should not be 'async'; expected a boolean return type.",
predicateReturnsNonBoolean: 'Predicate function should return a boolean.',
},
schema: [
{
Expand DownExpand Up@@ -275,6 +286,104 @@ export default createRule<Options, MessageId>({
if (assertedArgument != null) {
traverseNode(assertedArgument, true);
}
if (isArrayMethodCallWithPredicate(context, services, node)) {
const predicate = node.arguments.at(0);

if (predicate) {
checkArrayMethodCallPredicate(predicate);
}
}
}

/**
* Dedicated function to check array method predicate calls. Reports predicate
* arguments that don't return a boolean value.
*
* Ignores the `allow*` options and requires a boolean value.
*/
function checkArrayMethodCallPredicate(
predicateNode: TSESTree.CallExpressionArgument,
): void {
const isFunctionExpression = ASTUtils.isFunction(predicateNode);

// custom message for accidental `async` function expressions
if (isFunctionExpression && predicateNode.async) {
return context.report({
node: predicateNode,
messageId: 'predicateCannotBeAsync',
});
}

const returnTypes = services
.getTypeAtLocation(predicateNode)
.getCallSignatures()
.map(signature => {
const type = signature.getReturnType();

if (tsutils.isTypeParameter(type)) {
return checker.getBaseConstraintOfType(type) ?? type;
}

return type;
});

if (returnTypes.every(returnType => isBooleanType(returnType))) {
return;
}

const canFix = isFunctionExpression && !predicateNode.returnType;

return context.report({
node: predicateNode,
messageId: 'predicateReturnsNonBoolean',
suggest: canFix
? [
{
messageId: 'explicitBooleanReturnType',
fix: fixer => {
if (
predicateNode.type ===
AST_NODE_TYPES.ArrowFunctionExpression &&
isParenlessArrowFunction(predicateNode, context.sourceCode)
) {
return [
fixer.insertTextBefore(predicateNode.params[0], '('),
fixer.insertTextAfter(
predicateNode.params[0],
'): boolean',
),
];
}

if (predicateNode.params.length === 0) {
const closingBracket = nullThrows(
context.sourceCode.getFirstToken(
predicateNode,
token => token.value === ')',
),
'function expression has to have a closing parenthesis.',
);

return fixer.insertTextAfter(closingBracket, ': boolean');
}

const lastClosingParenthesis = nullThrows(
context.sourceCode.getTokenAfter(
predicateNode.params[predicateNode.params.length - 1],
token => token.value === ')',
),
'function expression has to have a closing parenthesis.',
);

return fixer.insertTextAfter(
lastClosingParenthesis,
': boolean',
);
},
},
]
: null,
});
}

/**
Expand DownExpand Up@@ -1007,11 +1116,13 @@ function isArrayLengthExpression(
function isBrandedBoolean(type: ts.Type): boolean {
return (
type.isIntersection() &&
type.types.some(childType =>
tsutils.isTypeFlagSet(
childType,
ts.TypeFlags.BooleanLiteral | ts.TypeFlags.Boolean,
),
)
type.types.some(childType => isBooleanType(childType))
);
}

function isBooleanType(expressionType: ts.Type): boolean {
return tsutils.isTypeFlagSet(
expressionType,
ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral,
);
}

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

Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp