β¬ οΈ Back to Table of Contents
π no-confusing-non-null-assertion¶
π Analysis Summary¶
| Metric | Count |
|---|---|
| π§ Functions | 4 |
| π¦ Imports | 7 |
| π Variables & Constants | 1 |
| π Type Aliases | 2 |
π Table of Contents¶
π οΈ File Location:¶
π packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts
π€ Default Export¶
| Property | Value |
|---|---|
name |
'no-confusing-non-null-assertion' |
meta.type |
'problem' |
meta.docs.description |
'Disallow non-null assertion in locations that may be confusing' |
meta.docs.recommended |
'stylistic' |
meta.hasSuggestions |
true |
meta.messages.confusingAssign |
'Confusing combination of non-null assertion and assignment like a! = b, which looks very similar to a != b.' |
meta.messages.confusingEqual |
'Confusing combination of non-null assertion and equality test like a! == b, which looks very similar to a !== b.' |
meta.messages.confusingOperator |
'Confusing combination of non-null assertion and {{operator}} operator like a! {{operator}} b, which might be mis... |
meta.messages.notNeedInAssign |
'Remove unnecessary non-null assertion (!) in assignment left-hand side.' |
meta.messages.notNeedInEqualTest |
'Remove unnecessary non-null assertion (!) in equality test.' |
meta.messages.notNeedInOperator |
'Remove possibly unnecessary non-null assertion (!) in the left operand of the {{operator}} operator.' |
meta.messages.wrapUpLeft |
'Wrap the left-hand side in parentheses to avoid confusion with "{{operator}}" operator.' |
meta.schema |
[] |
defaultOptions |
[] |
Entry point: create β documented under Functions.
π¦ Imports¶
| Name | Source |
|---|---|
TSESLint |
@typescript-eslint/utils |
TSESTree |
@typescript-eslint/utils |
ReportDescriptor |
@typescript-eslint/utils/ts-eslint |
RuleFix |
@typescript-eslint/utils/ts-eslint |
AST_NODE_TYPES |
@typescript-eslint/utils |
AST_TOKEN_TYPES |
@typescript-eslint/utils |
createRule |
../util |
Variables & Constants¶
| Name | Type | Kind | Value | Exported |
|---|---|---|---|---|
confusingOperators |
Set<"=" \| "==" \| "===" \| "in" \| "... |
const | new Set([ '=', '==', '===', 'in', 'instanceof', ] as const) |
β |
Functions¶
create(context: any): { 'BinaryExpression, AssignmentExpression'(node: TSESTree.A⦶
Parameters:
contextany
Returns: { 'BinaryExpression, AssignmentExpression'(node: TSESTree.AssignmentExpression | TSESTree.BinaryExpression): void; }
Calls:
isConfusingOperatorcontext.sourceCode.getLastTokencontext.sourceCode.getTokenAfterfixer.removewrapUpLeftFixercontext.reportconfusingOperatorToMessageData
Internal Comments:
// istanbul ignore next (x2)
// Look for a non-null assertion as the last token on the left hand side. (x2)
// That way, we catch things like `1 + two! === 3`, even though the left (x2)
// hand side isn't a non-null assertion AST node. (x2)
Code
create(context) {
function confusingOperatorToMessageData(
operator: ConfusingOperator,
): Pick<ReportDescriptor<MessageId>, 'data' | 'messageId'> {
switch (operator) {
case '=':
return {
messageId: 'confusingAssign',
};
case '==':
case '===':
return {
messageId: 'confusingEqual',
};
case 'in':
case 'instanceof':
return {
messageId: 'confusingOperator',
data: { operator },
};
// istanbul ignore next
default:
operator satisfies never;
throw new Error(`Unexpected operator ${operator as string}`);
}
}
return {
'BinaryExpression, AssignmentExpression'(
node: TSESTree.AssignmentExpression | TSESTree.BinaryExpression,
): void {
const operator = node.operator;
if (isConfusingOperator(operator)) {
// Look for a non-null assertion as the last token on the left hand side.
// That way, we catch things like `1 + two! === 3`, even though the left
// hand side isn't a non-null assertion AST node.
const leftHandFinalToken = context.sourceCode.getLastToken(node.left);
const tokenAfterLeft = context.sourceCode.getTokenAfter(node.left);
if (
leftHandFinalToken?.type === AST_TOKEN_TYPES.Punctuator &&
leftHandFinalToken.value === '!' &&
tokenAfterLeft?.value !== ')'
) {
if (node.left.type === AST_NODE_TYPES.TSNonNullExpression) {
let suggestions: TSESLint.SuggestionReportDescriptor<MessageId>[];
switch (operator) {
case '=':
suggestions = [
{
messageId: 'notNeedInAssign',
fix: (fixer): RuleFix => fixer.remove(leftHandFinalToken),
},
];
break;
case '==':
case '===':
suggestions = [
{
messageId: 'notNeedInEqualTest',
fix: (fixer): RuleFix => fixer.remove(leftHandFinalToken),
},
];
break;
case 'in':
case 'instanceof':
suggestions = [
{
messageId: 'notNeedInOperator',
data: { operator },
fix: (fixer): RuleFix => fixer.remove(leftHandFinalToken),
},
{
messageId: 'wrapUpLeft',
data: { operator },
fix: wrapUpLeftFixer(node),
},
];
break;
// istanbul ignore next
default:
operator satisfies never;
return;
}
context.report({
node,
...confusingOperatorToMessageData(operator),
suggest: suggestions,
});
} else {
context.report({
node,
...confusingOperatorToMessageData(operator),
suggest: [
{
messageId: 'wrapUpLeft',
data: { operator },
fix: wrapUpLeftFixer(node),
},
],
});
}
}
}
},
};
}
isConfusingOperator(operator: string): operator is ConfusingOperator¶
Parameters:
operatorstring
Returns: operator is ConfusingOperator
Calls:
confusingOperators.has
Code
wrapUpLeftFixer(node: TSESTree.AssignmentExpression | TSESTreβ¦): TSESLint.ReportFixFunction¶
Parameters:
nodeTSESTree.AssignmentExpression | TSESTree.BinaryExpression
Returns: TSESLint.ReportFixFunction
Calls:
fixer.insertTextBeforefixer.insertTextAfter
Code
Internal helpers¶
Declared inside another function in this file.
confusingOperatorToMessageData(operator: ConfusingOperator): Pick<ReportDescriptor<MessageId>, 'data' | 'messageId'>¶
Parameters:
operatorConfusingOperator
Returns: Pick<ReportDescriptor<MessageId>, 'data' | 'messageId'>
Internal Comments:
Code
function confusingOperatorToMessageData(
operator: ConfusingOperator,
): Pick<ReportDescriptor<MessageId>, 'data' | 'messageId'> {
switch (operator) {
case '=':
return {
messageId: 'confusingAssign',
};
case '==':
case '===':
return {
messageId: 'confusingEqual',
};
case 'in':
case 'instanceof':
return {
messageId: 'confusingOperator',
data: { operator },
};
// istanbul ignore next
default:
operator satisfies never;
throw new Error(`Unexpected operator ${operator as string}`);
}
}
Type Aliases¶
MessageId¶
type MessageId = | 'confusingAssign'
| 'confusingEqual'
| 'confusingOperator'
| 'notNeedInAssign'
| 'notNeedInEqualTest'
| 'notNeedInOperator'
| 'wrapUpLeft';
ConfusingOperator¶
Generated by Syntax Scribe