-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat(eslint-plugin): [switch-exhaustiveness-check] add support for "no default" comment #10218
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b465b39
a590cfd
d394fd3
cfb6ddc
5761456
1e9aa95
6844c0f
88fad95
966aebe
764fd6b
e8ed38f
c7f743b
175681c
cbb3f81
ebb20f8
844a96c
f4709a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,9 +14,11 @@ import { | |
requiresQuoting, | ||
} from '../util'; | ||
|
||
const DEFAULT_COMMENT_PATTERN = /^no default$/iu; | ||
JoshuaKGoldberg marked this conversation as resolved.
Show resolved
Hide resolved
JoshuaKGoldberg marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there's a default value, please specify it in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. �In order to put a default value in defaultOptions, the defaultCaseCommentPattern option must be able to receive a flag. Therefore, this option should be in the form of an array, with an expression at the first index and a flag at the second index.
Previously, the default value was treated as a separate variable because of equivalence with eslint rules. Would there be any problem with implementing it like this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As much as I would love to keep things to the |
||
|
||
interface SwitchMetadata { | ||
readonly containsNonLiteralType: boolean; | ||
readonly defaultCase: TSESTree.SwitchCase | undefined; | ||
readonly defaultCase: TSESTree.Comment | TSESTree.SwitchCase | undefined; | ||
readonly missingLiteralBranchTypes: ts.Type[]; | ||
readonly symbolName: string | undefined; | ||
} | ||
|
@@ -38,6 +40,11 @@ type Options = [ | |
*/ | ||
requireDefaultForNonUnion?: boolean; | ||
|
||
/** | ||
* Regular expression for a comment that can indicate an intentionally omitted default case. | ||
*/ | ||
defaultCaseCommentPattern?: string; | ||
|
||
/** | ||
* If `true`, the `default` clause is used to determine whether the switch statement is exhaustive for union types. | ||
* | ||
|
@@ -81,6 +88,10 @@ export default createRule<Options, MessageIds>({ | |
type: 'boolean', | ||
description: `If 'true', the 'default' clause is used to determine whether the switch statement is exhaustive for union type`, | ||
}, | ||
defaultCaseCommentPattern: { | ||
type: 'string', | ||
description: `Regular expression for a comment that can indicate an intentionally omitted default case.`, | ||
}, | ||
requireDefaultForNonUnion: { | ||
type: 'boolean', | ||
description: `If 'true', require a 'default' clause for switches on non-union types.`, | ||
|
@@ -102,13 +113,34 @@ export default createRule<Options, MessageIds>({ | |
{ | ||
allowDefaultCaseForExhaustiveSwitch, | ||
considerDefaultExhaustiveForUnions, | ||
defaultCaseCommentPattern, | ||
requireDefaultForNonUnion, | ||
}, | ||
], | ||
) { | ||
const services = getParserServices(context); | ||
const checker = services.program.getTypeChecker(); | ||
const compilerOptions = services.program.getCompilerOptions(); | ||
const commentRegExp = | ||
defaultCaseCommentPattern != null | ||
? new RegExp(defaultCaseCommentPattern, 'u') | ||
: DEFAULT_COMMENT_PATTERN; | ||
|
||
function getCommentDefaultCase( | ||
node: TSESTree.SwitchStatement, | ||
): TSESTree.Comment | undefined { | ||
const lastCase = node.cases.at(-1); | ||
const commentsAfterLastCase = lastCase | ||
? context.sourceCode.getCommentsAfter(lastCase) | ||
: []; | ||
const defaultCaseComment = commentsAfterLastCase.at(-1); | ||
|
||
if (commentRegExp.test(defaultCaseComment?.value.trim() || '')) { | ||
return defaultCaseComment; | ||
} | ||
|
||
return; | ||
} | ||
|
||
function getSwitchMetadata(node: TSESTree.SwitchStatement): SwitchMetadata { | ||
const defaultCase = node.cases.find( | ||
|
@@ -170,7 +202,7 @@ export default createRule<Options, MessageIds>({ | |
|
||
return { | ||
containsNonLiteralType, | ||
defaultCase, | ||
defaultCase: defaultCase ?? getCommentDefaultCase(node), | ||
missingLiteralBranchTypes, | ||
symbolName, | ||
}; | ||
|
@@ -210,6 +242,7 @@ export default createRule<Options, MessageIds>({ | |
fixer, | ||
node, | ||
missingLiteralBranchTypes, | ||
defaultCase, | ||
symbolName?.toString(), | ||
); | ||
}, | ||
|
@@ -223,11 +256,11 @@ export default createRule<Options, MessageIds>({ | |
fixer: TSESLint.RuleFixer, | ||
node: TSESTree.SwitchStatement, | ||
missingBranchTypes: (ts.Type | null)[], // null means default branch | ||
defaultCase: TSESTree.Comment | TSESTree.SwitchCase | undefined, | ||
symbolName?: string, | ||
): TSESLint.RuleFix { | ||
const lastCase = | ||
node.cases.length > 0 ? node.cases[node.cases.length - 1] : null; | ||
const defaultCase = node.cases.find(caseEl => caseEl.test == null); | ||
|
||
const caseIndent = lastCase | ||
? ' '.repeat(lastCase.loc.start.column) | ||
|
@@ -349,7 +382,7 @@ export default createRule<Options, MessageIds>({ | |
{ | ||
messageId: 'addMissingCases', | ||
fix(fixer): TSESLint.RuleFix { | ||
return fixSwitch(fixer, node, [null]); | ||
return fixSwitch(fixer, node, [null], defaultCase); | ||
}, | ||
}, | ||
], | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.