Skip to content

Commit 9ce4f40

Browse files
fix: handle namespace import too
1 parent cb20606 commit 9ce4f40

File tree

2 files changed

+61
-44
lines changed

2 files changed

+61
-44
lines changed

src/rules/no-ignored-default-value.ts

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { TSESTree as es, ESLintUtils } from '@typescript-eslint/utils';
2-
import { getTypeServices, isIdentifier, isImport, isMemberExpression, isObjectExpression, isProperty } from '../etc';
2+
import { getTypeServices, isIdentifier, isMemberExpression, isObjectExpression, isProperty } from '../etc';
33
import { ruleCreator } from '../utils';
44

55
export const noIgnoredDefaultValueRule = ruleCreator({
@@ -18,7 +18,7 @@ export const noIgnoredDefaultValueRule = ruleCreator({
1818
name: 'no-ignored-default-value',
1919
create: (context) => {
2020
const { getTypeAtLocation } = ESLintUtils.getParserServices(context);
21-
const { couldBeObservable } = getTypeServices(context);
21+
const { couldBeObservable, couldBeType } = getTypeServices(context);
2222

2323
function checkConfigObj(configArg: es.ObjectExpression) {
2424
if (!configArg.properties.some(p => isProperty(p) && isIdentifier(p.key) && p.key.name === 'defaultValue')) {
@@ -39,13 +39,25 @@ export const noIgnoredDefaultValueRule = ruleCreator({
3939
}
4040
}
4141

42-
function checkFunctionArgs(callExpression: es.CallExpression, reportNode: es.Node) {
43-
const scope = context.sourceCode.getScope(callExpression);
44-
if (!isImport(scope, 'firstValueFrom', /^rxjs\/?/)
45-
&& !isImport(scope, 'lastValueFrom', /^rxjs\/?/)) {
42+
function checkArg(arg: es.Node) {
43+
if (isIdentifier(arg)) {
44+
checkConfigType(arg);
45+
return;
46+
} else if (isMemberExpression(arg) && isIdentifier(arg.property)) {
47+
checkConfigType(arg.property);
48+
return;
49+
}
50+
if (!isObjectExpression(arg)) {
51+
return;
52+
}
53+
checkConfigObj(arg);
54+
}
55+
56+
function checkFunctionArgs(node: es.Node, args: es.CallExpressionArgument[]) {
57+
if (!couldBeType(node, 'firstValueFrom', { name: /[/\\]rxjs[/\\]/ })
58+
&& !couldBeType(node, 'lastValueFrom', { name: /[/\\]rxjs[/\\]/ })) {
4659
return;
4760
}
48-
const { arguments: args } = callExpression;
4961
if (!args || args.length <= 0) {
5062
return;
5163
}
@@ -56,62 +68,44 @@ export const noIgnoredDefaultValueRule = ruleCreator({
5668
if (!configArg) {
5769
context.report({
5870
messageId: 'forbidden',
59-
node: reportNode,
71+
node,
6072
});
6173
return;
6274
}
63-
if (isIdentifier(configArg)) {
64-
checkConfigType(configArg);
65-
return;
66-
} else if (isMemberExpression(configArg) && isIdentifier(configArg.property)) {
67-
checkConfigType(configArg.property);
68-
return;
69-
}
70-
if (!isObjectExpression(configArg)) {
71-
return;
72-
}
73-
checkConfigObj(configArg);
75+
checkArg(configArg);
7476
}
7577

76-
function checkOperatorArgs(callExpression: es.CallExpression, reportNode: es.Node) {
77-
const scope = context.sourceCode.getScope(callExpression);
78-
if (!isImport(scope, 'first', /^rxjs\/?/)
79-
&& !isImport(scope, 'last', /^rxjs\/?/)) {
78+
function checkOperatorArgs(node: es.Node, args: es.CallExpressionArgument[]) {
79+
if (!couldBeType(node, 'first', { name: /[/\\]rxjs[/\\]/ })
80+
&& !couldBeType(node, 'last', { name: /[/\\]rxjs[/\\]/ })) {
8081
return;
8182
}
82-
const { arguments: args } = callExpression;
8383

8484
if (!args || args.length <= 0) {
8585
context.report({
8686
messageId: 'forbidden',
87-
node: reportNode,
87+
node,
8888
});
8989
return;
9090
}
9191
const [arg] = args;
92-
if (isIdentifier(arg)) {
93-
checkConfigType(arg);
94-
return;
95-
} else if (isMemberExpression(arg) && isIdentifier(arg.property)) {
96-
checkConfigType(arg.property);
97-
return;
98-
}
99-
if (!isObjectExpression(arg)) {
100-
return;
101-
}
102-
checkConfigObj(arg);
92+
checkArg(arg);
10393
}
10494

10595
return {
106-
'CallExpression[callee.name=/^(firstValueFrom|lastValueFrom)$/]': (
107-
node: es.CallExpression,
108-
) => {
109-
checkFunctionArgs(node, node.callee);
96+
'CallExpression[callee.name=/^(firstValueFrom|lastValueFrom)$/]': (node: es.CallExpression) => {
97+
checkFunctionArgs(node.callee, node.arguments);
98+
},
99+
'CallExpression[callee.property.name=/^(firstValueFrom|lastValueFrom)$/]': (node: es.CallExpression) => {
100+
const memberExpression = node.callee as es.MemberExpression;
101+
checkFunctionArgs(memberExpression.property, node.arguments);
102+
},
103+
'CallExpression[callee.property.name=\'pipe\'] > CallExpression[callee.name=/^(first|last)$/]': (node: es.CallExpression) => {
104+
checkOperatorArgs(node.callee, node.arguments);
110105
},
111-
'CallExpression[callee.property.name=\'pipe\'] > CallExpression[callee.name=/^(first|last)$/]': (
112-
node: es.CallExpression,
113-
) => {
114-
checkOperatorArgs(node, node.callee);
106+
'CallExpression[callee.property.name=\'pipe\'] > CallExpression[callee.property.name=/^(first|last)$/]': (node: es.CallExpression) => {
107+
const memberExpression = node.callee as es.MemberExpression;
108+
checkOperatorArgs(memberExpression.property, node.arguments);
115109
},
116110
};
117111
},

tests/rules/no-ignored-default-value.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,28 @@ ruleTester({ types: true }).run('no-ignored-default-value', noIgnoredDefaultValu
139139
~~~~ [forbidden]
140140
`,
141141
),
142+
fromFixture(
143+
stripIndent`
144+
// namespace import
145+
import * as Rx from "rxjs";
146+
147+
Rx.firstValueFrom(Rx.of(42));
148+
~~~~~~~~~~~~~~ [forbidden]
149+
Rx.of(42).pipe(Rx.first());
150+
~~~~~ [forbidden]
151+
`,
152+
),
153+
fromFixture(
154+
stripIndent`
155+
// operators import (deprecated)
156+
import { of } from "rxjs";
157+
import { first, last } from "rxjs/operators";
158+
159+
of(42).pipe(first());
160+
~~~~~ [forbidden]
161+
of(42).pipe(last());
162+
~~~~ [forbidden]
163+
`,
164+
),
142165
],
143166
});

0 commit comments

Comments
 (0)