Skip to content

Commit fa5e846

Browse files
feat(no-misused-observables): sub-options for void return
1 parent 8ffb56a commit fa5e846

File tree

3 files changed

+114
-26
lines changed

3 files changed

+114
-26
lines changed

docs/rules/no-misused-observables.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,22 @@
66

77
## Options
88

9-
<!-- begin auto-generated rule options list -->
9+
<!-- WARNING: not auto-generated! -->
1010

11-
| Name | Description | Type | Default |
12-
| :----------------- | :-------------------------------------------------------------------------- | :------ | :------ |
13-
| `checksSpreads` | Disallow `...` spreading an Observable. | Boolean | `true` |
14-
| `checksVoidReturn` | Disallow returning an Observable from a function typed as returning `void`. | Boolean | `true` |
11+
| Name | Description | Type | Default |
12+
| :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | :------ | :------ |
13+
| `checksSpreads` | Disallow `...` spreading an Observable. | Boolean | `true` |
14+
| `checksVoidReturn` | Disallow returning an Observable from a function typed as returning `void`. | Object | `true` |
1515

16-
<!-- end auto-generated rule options list -->
16+
### `checksVoidReturn`
17+
18+
You can disable selective parts of the `checksVoidReturn` option. The following sub-options are supported:
19+
20+
| Name | Description | Type | Default |
21+
| :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | :------ | :------ |
22+
| `arguments` | Disallow passing an Observable-returning function as an argument where the parameter type expects a function that returns `void`. | Boolean | `true` |
23+
| `attributes` | Disallow passing an Observable-returning function as a JSX attribute expected to be a function that returns `void`. | Boolean | `true` |
24+
| `inheritedMethods` | Disallow providing an Observable-returning function where a function that returns `void` is expected by an extended or implemented type. | Boolean | `true` |
25+
| `properties` | Disallow providing an Observable-returning function where a function that returns `void` is expected by a property. | Boolean | `true` |
26+
| `returns` | Disallow returning an Observable-returning function where a function that returns `void` is expected. | Boolean | `true` |
27+
| `variables` | Disallow assigning or declaring an Observable-returning function where a function that returns `void` is expected. | Boolean | `true` |

src/rules/no-misused-observables.ts

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,48 @@ import { ruleCreator } from '../utils';
1515
// The implementation of this rule is similar to typescript-eslint's no-misused-promises. MIT License.
1616
// https://github.com/typescript-eslint/typescript-eslint/blob/fcd6cf063a774f73ea00af23705117a197f826d4/packages/eslint-plugin/src/rules/no-misused-promises.ts
1717

18+
// This is only exported for dts build to work.
19+
export interface ChecksVoidReturnOptions {
20+
arguments?: boolean;
21+
attributes?: boolean;
22+
inheritedMethods?: boolean;
23+
properties?: boolean;
24+
returns?: boolean;
25+
variables?: boolean;
26+
}
27+
28+
function parseChecksVoidReturn(
29+
checksVoidReturn: boolean | ChecksVoidReturnOptions,
30+
): ChecksVoidReturnOptions | false {
31+
switch (checksVoidReturn) {
32+
case false:
33+
return false;
34+
35+
case true:
36+
case undefined:
37+
return {
38+
arguments: true,
39+
attributes: true,
40+
inheritedMethods: true,
41+
properties: true,
42+
returns: true,
43+
variables: true,
44+
};
45+
46+
default:
47+
return {
48+
arguments: checksVoidReturn.arguments ?? true,
49+
attributes: checksVoidReturn.attributes ?? true,
50+
inheritedMethods: checksVoidReturn.inheritedMethods ?? true,
51+
properties: checksVoidReturn.properties ?? true,
52+
returns: checksVoidReturn.returns ?? true,
53+
variables: checksVoidReturn.variables ?? true,
54+
};
55+
}
56+
}
57+
1858
const defaultOptions: readonly {
19-
checksVoidReturn?: boolean;
59+
checksVoidReturn?: boolean | ChecksVoidReturnOptions;
2060
checksSpreads?: boolean;
2161
}[] = [];
2262

@@ -39,7 +79,30 @@ export const noMisusedObservablesRule = ruleCreator({
3979
schema: [
4080
{
4181
properties: {
42-
checksVoidReturn: { type: 'boolean', default: true, description: 'Disallow returning an Observable from a function typed as returning `void`.' },
82+
checksVoidReturn: {
83+
default: true,
84+
description: 'Disallow returning an Observable from a function typed as returning `void`.',
85+
oneOf: [
86+
{
87+
default: true,
88+
type: 'boolean',
89+
description: 'Disallow returning an Observable from all types of functions typed as returning `void`.',
90+
},
91+
{
92+
type: 'object',
93+
additionalProperties: false,
94+
description: 'Which forms of functions may have checking disabled.',
95+
properties: {
96+
arguments: { type: 'boolean', description: 'Disallow passing an Observable-returning function as an argument where the parameter type expects a function that returns `void`.' },
97+
attributes: { type: 'boolean', description: 'Disallow passing an Observable-returning function as a JSX attribute expected to be a function that returns `void`.' },
98+
inheritedMethods: { type: 'boolean', description: 'Disallow providing an Observable-returning function where a function that returns `void` is expected by an extended or implemented type.' },
99+
properties: { type: 'boolean', description: 'Disallow providing an Observable-returning function where a function that returns `void` is expected by a property.' },
100+
returns: { type: 'boolean', description: 'Disallow returning an Observable-returning function where a function that returns `void` is expected.' },
101+
variables: { type: 'boolean', description: 'Disallow assigning or declaring an Observable-returning function where a function that returns `void` is expected.' },
102+
},
103+
},
104+
],
105+
},
43106
checksSpreads: { type: 'boolean', default: true, description: 'Disallow `...` spreading an Observable.' },
44107
},
45108
type: 'object',
@@ -55,18 +118,32 @@ export const noMisusedObservablesRule = ruleCreator({
55118
const [config = {}] = context.options;
56119
const { checksVoidReturn = true, checksSpreads = true } = config;
57120

58-
const voidReturnChecks: eslint.RuleListener = {
59-
CallExpression: checkArguments,
60-
NewExpression: checkArguments,
61-
JSXAttribute: checkJSXAttribute,
62-
ClassDeclaration: checkClassLikeOrInterfaceNode,
63-
ClassExpression: checkClassLikeOrInterfaceNode,
64-
TSInterfaceDeclaration: checkClassLikeOrInterfaceNode,
65-
Property: checkProperty,
66-
ReturnStatement: checkReturnStatement,
67-
AssignmentExpression: checkAssignment,
68-
VariableDeclarator: checkVariableDeclaration,
69-
};
121+
const parsedChecksVoidReturn = parseChecksVoidReturn(checksVoidReturn);
122+
123+
const voidReturnChecks: eslint.RuleListener = parsedChecksVoidReturn ? {
124+
...(parsedChecksVoidReturn.arguments && {
125+
CallExpression: checkArguments,
126+
NewExpression: checkArguments,
127+
}),
128+
...(parsedChecksVoidReturn.attributes && {
129+
JSXAttribute: checkJSXAttribute,
130+
}),
131+
...(parsedChecksVoidReturn.inheritedMethods && {
132+
ClassDeclaration: checkClassLikeOrInterfaceNode,
133+
ClassExpression: checkClassLikeOrInterfaceNode,
134+
TSInterfaceDeclaration: checkClassLikeOrInterfaceNode,
135+
}),
136+
...(parsedChecksVoidReturn.properties && {
137+
Property: checkProperty,
138+
}),
139+
...(parsedChecksVoidReturn.returns && {
140+
ReturnStatement: checkReturnStatement,
141+
}),
142+
...(parsedChecksVoidReturn.variables && {
143+
AssignmentExpression: checkAssignment,
144+
VariableDeclarator: checkVariableDeclaration,
145+
}),
146+
} : {};
70147

71148
const spreadChecks: eslint.RuleListener = {
72149
SpreadElement: (node) => {

tests/rules/no-misused-observables.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
1919
}
2020
new Foo(() => of(42));
2121
`,
22-
options: [{ checksVoidReturn: false }],
22+
options: [{ checksVoidReturn: { arguments: false } }],
2323
},
2424
stripIndent`
2525
// void return argument; unrelated
@@ -53,7 +53,7 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
5353
);
5454
};
5555
`,
56-
options: [{ checksVoidReturn: false }],
56+
options: [{ checksVoidReturn: { attributes: false } }],
5757
languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
5858
},
5959
{
@@ -93,7 +93,7 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
9393
foo(): Observable<number>;
9494
}
9595
`,
96-
options: [{ checksVoidReturn: false }],
96+
options: [{ checksVoidReturn: { inheritedMethods: false } }],
9797
},
9898
stripIndent`
9999
// void return inherited method; not void
@@ -140,7 +140,7 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
140140
c(): Observable<number> { return of(42); },
141141
};
142142
`,
143-
options: [{ checksVoidReturn: false }],
143+
options: [{ checksVoidReturn: { properties: false } }],
144144
},
145145
stripIndent`
146146
// void return property; not void
@@ -185,7 +185,7 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
185185
return (): Observable<number> => of(42);
186186
}
187187
`,
188-
options: [{ checksVoidReturn: false }],
188+
options: [{ checksVoidReturn: { returns: false } }],
189189
},
190190
stripIndent`
191191
// void return return value; not void
@@ -215,7 +215,7 @@ ruleTester({ types: true }).run('no-misused-observables', noMisusedObservablesRu
215215
foo = (): Observable<number> => of(42);
216216
const bar: () => void = (): Observable<number> => of(42);
217217
`,
218-
options: [{ checksVoidReturn: false }],
218+
options: [{ checksVoidReturn: { variables: false } }],
219219
},
220220
stripIndent`
221221
// void return variable; not void

0 commit comments

Comments
 (0)