Skip to content
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

feat(eslint-plugin): [strict-boolean-expressions] add allow nullable enum to strict boolean expressions #6096

Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8f08063
feat: add allowNullableEnum option
kazizi55 Nov 26, 2022
1193d70
test: add allowNullableEnum option
kazizi55 Nov 26, 2022
99bc303
Merge branch 'main' into add-allowNullableEnum-to-strict-boolean-expr…
kazizi55 Nov 26, 2022
14ba8ac
fix: lint error
kazizi55 Nov 26, 2022
d7df053
chore: erase indent diff
kazizi55 Nov 26, 2022
a0b643c
fix: error column number
kazizi55 Nov 26, 2022
15e108e
test: fix output
kazizi55 Nov 26, 2022
a875552
test: fix output format
kazizi55 Nov 26, 2022
8d0c41d
Merge branch 'main' into add-allowNullableEnum-to-strict-boolean-expr…
kazizi55 Nov 27, 2022
3c806a1
test: add !nullableEnum pattern
kazizi55 Nov 27, 2022
42d3371
Update packages/eslint-plugin/src/rules/strict-boolean-expressions.ts
kazizi55 Nov 29, 2022
0c9370f
Update packages/eslint-plugin/tests/rules/strict-boolean-expressions.…
kazizi55 Nov 29, 2022
ebc2351
chore: yarn lint --fix
kazizi55 Dec 3, 2022
aa2e949
perf: use some instead of length
kazizi55 Dec 3, 2022
20a00dc
test: fix output
kazizi55 Dec 3, 2022
fae50f4
test: split into two cases
kazizi55 Dec 3, 2022
2b71e6c
docs: add allowNullableEnum
kazizi55 Dec 3, 2022
b02da7c
Merge branch 'main' into add-allowNullableEnum-to-strict-boolean-expr…
kazizi55 Dec 3, 2022
3e4ad5d
Update packages/eslint-plugin/src/rules/strict-boolean-expressions.ts
kazizi55 Dec 28, 2022
be467ba
perf: use some instead of filter
kazizi55 Dec 28, 2022
3803cc0
Update packages/eslint-plugin/docs/rules/strict-boolean-expressions.md
kazizi55 Jan 2, 2023
e5a4e1f
Update packages/eslint-plugin/docs/rules/strict-boolean-expressions.md
kazizi55 Jan 2, 2023
68c49a8
Update packages/eslint-plugin/src/rules/strict-boolean-expressions.ts
kazizi55 Jan 2, 2023
02ec998
test: add case
kazizi55 Jan 2, 2023
39863e0
fix: add string condition
kazizi55 Jan 7, 2023
8ef51cf
Merge branch 'main' into add-allowNullableEnum-to-strict-boolean-expr…
kazizi55 Jan 7, 2023
b4ae4f6
Merge branch 'main' into add-allowNullableEnum-to-strict-boolean-expr…
JoshuaKGoldberg Feb 4, 2023
302f4b5
Fix lil lint issue
JoshuaKGoldberg Feb 4, 2023
c19c528
Test fix
JoshuaKGoldberg Feb 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 50 additions & 0 deletions packages/eslint-plugin/src/rules/strict-boolean-expressions.ts
Expand Up @@ -13,6 +13,7 @@ export type Options = [
allowNullableBoolean?: boolean;
allowNullableString?: boolean;
allowNullableNumber?: boolean;
allowNullableEnum?: boolean;
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
allowAny?: boolean;
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
},
Expand All @@ -29,6 +30,7 @@ export type MessageId =
| 'conditionErrorNullableNumber'
| 'conditionErrorObject'
| 'conditionErrorNullableObject'
| 'conditionErrorNullableEnum'
| 'noStrictNullCheck'
| 'conditionFixDefaultFalse'
| 'conditionFixDefaultEmptyString'
Expand Down Expand Up @@ -63,6 +65,7 @@ export default util.createRule<Options, MessageId>({
allowNullableBoolean: { type: 'boolean' },
allowNullableString: { type: 'boolean' },
allowNullableNumber: { type: 'boolean' },
allowNullableEnum: { type: 'boolean' },
allowAny: { type: 'boolean' },
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: {
type: 'boolean',
Expand Down Expand Up @@ -102,6 +105,9 @@ export default util.createRule<Options, MessageId>({
conditionErrorNullableObject:
'Unexpected nullable object value in conditional. ' +
'An explicit null check is required.',
conditionErrorNullableEnum:
'Unexpected nullable enum value in conditional. ' +
'Please handle the nullish/zero/NaN cases explicitly.',
noStrictNullCheck:
'This rule requires the `strictNullChecks` compiler option to be turned on to function correctly.',

Expand Down Expand Up @@ -137,6 +143,7 @@ export default util.createRule<Options, MessageId>({
allowNullableBoolean: false,
allowNullableString: false,
allowNullableNumber: false,
allowNullableEnum: true,
allowAny: false,
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false,
},
Expand Down Expand Up @@ -718,6 +725,37 @@ export default util.createRule<Options, MessageId>({
return;
}

// nullable enum
if (is('nullish', 'number', 'enum')) {
if (!options.allowNullableEnum) {
if (isLogicalNegationExpression(node.parent!)) {
// if (!nullableEnum)
kazizi55 marked this conversation as resolved.
Show resolved Hide resolved
context.report({
node,
messageId: 'conditionErrorNullableEnum',
fix: util.getWrappingFixer({
sourceCode,
node: node.parent,
innerNode: node,
wrap: code => `${code} == null`,
}),
});
} else {
// if (nullableEnum)
kazizi55 marked this conversation as resolved.
Show resolved Hide resolved
context.report({
node,
messageId: 'conditionErrorNullableEnum',
fix: util.getWrappingFixer({
sourceCode,
node,
wrap: code => `${code} != null`,
}),
});
}
}
return;
}

// any
if (is('any')) {
if (!options.allowAny) {
Expand Down Expand Up @@ -753,6 +791,7 @@ export default util.createRule<Options, MessageId>({
| 'number'
| 'truthy number'
| 'object'
| 'enum'
| 'any'
| 'never';

Expand Down Expand Up @@ -814,6 +853,17 @@ export default util.createRule<Options, MessageId>({
}
}

const enums = types.filter(type =>
tsutils.isTypeFlagSet(
type,
ts.TypeFlags.Enum | ts.TypeFlags.EnumLike | ts.TypeFlags.EnumLiteral,
kazizi55 marked this conversation as resolved.
Show resolved Hide resolved
),
);

if (enums.length) {
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
variantTypes.add('enum');
}

if (
types.some(
type =>
Expand Down
Expand Up @@ -133,6 +133,25 @@ ruleTester.run('strict-boolean-expressions', rule, {
`,
}),

// nullable enum in boolean context
{
code: `
enum ExampleEnum {
This = 0,
That = 1,
}
const rand = Math.random();
let theEnum: ExampleEnum | null = null;
if (rand < 0.3) {
theEnum = ExampleEnum.This;
}
if (theEnum) {
}
if (!theEnum) {
}
`,
options: [{ allowNullableEnum: true }],
},
{
code: `
declare const x: string[] | null;
Expand Down Expand Up @@ -965,6 +984,56 @@ if (y) {
],
}),

// nullable enum in boolean context
{
options: [{ allowNullableEnum: false }],
code: `
enum ExampleEnum {
This = 0,
That = 1,
}
const rand = Math.random();
let theEnum: ExampleEnum | null = null;
if (rand < 0.3) {
theEnum = ExampleEnum.This;
}
kazizi55 marked this conversation as resolved.
Show resolved Hide resolved
if (theEnum) {
}
if (!theEnum) {
}
`,
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
errors: [
{
line: 11,
column: 13,
messageId: 'conditionErrorNullableEnum',
endLine: 11,
endColumn: 20,
},
{
line: 13,
column: 14,
messageId: 'conditionErrorNullableEnum',
endLine: 13,
endColumn: 21,
},
],
output: `
enum ExampleEnum {
This = 0,
That = 1,
}
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
const rand = Math.random();
let theEnum: ExampleEnum | null = null;
if (rand < 0.3) {
theEnum = ExampleEnum.This;
}
if (theEnum != null) {
}
if (theEnum == null) {
}
`,
},
// any in boolean context
...batchedSingleLineTests<MessageId, Options>({
code: noFormat`
Expand Down