Skip to content

Commit

Permalink
fix(eslint-plugin): support inject for no-typed-global-store rule (#3951
Browse files Browse the repository at this point in the history
)
  • Loading branch information
timdeschryver committed Jul 11, 2023
1 parent a1576de commit d3e84d8
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 31 deletions.
55 changes: 51 additions & 4 deletions modules/eslint-plugin/spec/rules/no-typed-global-store.spec.ts
Expand Up @@ -14,7 +14,7 @@ type MessageIds = ESLintUtils.InferMessageIdsTypeFromRule<typeof rule>;
type Options = ESLintUtils.InferOptionsTypeFromRule<typeof rule>;
type RunTests = TSESLint.RunTests<MessageIds, Options>;

const valid: () => RunTests['valid'] = () => [
const validConstructor: () => RunTests['valid'] = () => [
`
import { Store } from '@ngrx/store'
Expand All @@ -23,7 +23,27 @@ export class Ok {
}`,
];

const invalid: () => RunTests['invalid'] = () => [
const validInject: () => RunTests['valid'] = () => [
// https://github.com/ngrx/platform/issues/3950
`
import { inject } from '@angular/core';
import { Store } from '@ngrx/store';
export class AppComponent {
store = inject(Store);
otherName = inject(Store);
}`,
`
import { somethingElse } from '@angular/core';
import { Store } from '@ngrx/store';
export class AppComponent {
store = somethingElse(Store<{}>);
}
`,
];

const invalidConstructor: () => RunTests['invalid'] = () => [
fromFixture(
`
import { Store } from '@ngrx/store'
Expand Down Expand Up @@ -124,7 +144,34 @@ class NotOk3 {
),
];

const invalidInject: () => RunTests['invalid'] = () => [
fromFixture(
`
import { inject } from '@angular/core';
import { Store } from '@ngrx/store';
export class NotOk4 {
store = inject(Store<{}>);
~~~~ [${noTypedStore} suggest]
}`,
{
suggestions: [
{
messageId: noTypedStoreSuggest,
output: `
import { inject } from '@angular/core';
import { Store } from '@ngrx/store';
export class NotOk4 {
store = inject(Store);
}`,
},
],
}
),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: valid(),
invalid: invalid(),
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
});
61 changes: 43 additions & 18 deletions modules/eslint-plugin/src/rules/store/no-typed-global-store.ts
@@ -1,6 +1,13 @@
import * as path from 'path';
import { createRule } from '../../rule-creator';
import { getNgRxStores, isTSTypeReference } from '../../utils';
import {
getNgRxStores,
isPropertyDefinition,
isTSTypeReference,
isCallExpression,
isTSInstantiationExpression,
} from '../../utils';
import type { TSESTree } from '@typescript-eslint/experimental-utils';

export const noTypedStore = 'noTypedStore';
export const noTypedStoreSuggest = 'noTypedStoreSuggest';
Expand Down Expand Up @@ -32,30 +39,48 @@ export default createRule<Options, MessageIds>({
Program() {
const { identifiers = [] } = getNgRxStores(context);

for (const {
typeAnnotation: { typeAnnotation },
} of identifiers) {
for (const identifier of identifiers) {
// using inject()
if (!identifier.typeAnnotation) {
const { parent } = identifier;
if (
isPropertyDefinition(parent) &&
parent.value &&
isCallExpression(parent.value) &&
parent.value.arguments.length
) {
const [storeArgument] = parent.value.arguments;
if (isTSInstantiationExpression(storeArgument)) {
report(storeArgument.typeParameters);
}
}

continue;
}

if (
!isTSTypeReference(typeAnnotation) ||
!typeAnnotation.typeParameters
!isTSTypeReference(identifier.typeAnnotation.typeAnnotation) ||
!identifier.typeAnnotation.typeAnnotation.typeParameters
) {
continue;
}

const { typeParameters } = typeAnnotation;

context.report({
node: typeParameters,
messageId: noTypedStore,
suggest: [
{
messageId: noTypedStoreSuggest,
fix: (fixer) => fixer.remove(typeParameters),
},
],
});
report(identifier.typeAnnotation.typeAnnotation.typeParameters);
}
},
};

function report(typeParameters: TSESTree.TSTypeParameterInstantiation) {
context.report({
node: typeParameters,
messageId: noTypedStore,
suggest: [
{
messageId: noTypedStoreSuggest,
fix: (fixer) => fixer.remove(typeParameters),
},
],
});
}
},
});
3 changes: 3 additions & 0 deletions modules/eslint-plugin/src/utils/helper-functions/guards.ts
Expand Up @@ -42,6 +42,9 @@ export const isTSParameterProperty = isNodeOfType(
);
export const isTSTypeAnnotation = isNodeOfType(AST_NODE_TYPES.TSTypeAnnotation);
export const isTSTypeReference = isNodeOfType(AST_NODE_TYPES.TSTypeReference);
export const isTSInstantiationExpression = isNodeOfType(
AST_NODE_TYPES.TSInstantiationExpression
);
export const isObjectExpression = isNodeOfType(AST_NODE_TYPES.ObjectExpression);
export const isProperty = isNodeOfType(AST_NODE_TYPES.Property);

Expand Down
26 changes: 17 additions & 9 deletions modules/eslint-plugin/src/utils/helper-functions/utils.ts
Expand Up @@ -17,6 +17,7 @@ import {
isTSTypeReference,
isTemplateElement,
isTemplateLiteral,
isTSInstantiationExpression,
} from './guards';
import { NGRX_MODULE_PATHS } from './ngrx-modules';

Expand Down Expand Up @@ -331,8 +332,11 @@ function getInjectedParametersWithSourceCode(
const identifiers = typedVariable?.references?.reduce<
readonly InjectedParameter[]
>((identifiers, { identifier: { parent } }) => {
if (!parent) {
return identifiers;
}

if (
parent &&
isTSTypeReference(parent) &&
parent.parent &&
isTSTypeAnnotation(parent.parent) &&
Expand All @@ -342,17 +346,21 @@ function getInjectedParametersWithSourceCode(
return identifiers.concat(parent.parent.parent as InjectedParameter);
}

const parentToCheck = isTSInstantiationExpression(parent)
? parent.parent
: parent;

if (
parent &&
isCallExpression(parent) &&
isIdentifier(parent.callee) &&
parent.callee.name == 'inject' &&
parent.parent &&
isPropertyDefinition(parent.parent) &&
isIdentifier(parent.parent.key) &&
parentToCheck &&
isCallExpression(parentToCheck) &&
isIdentifier(parentToCheck.callee) &&
parentToCheck.callee.name == 'inject' &&
parentToCheck.parent &&
isPropertyDefinition(parentToCheck.parent) &&
isIdentifier(parentToCheck.parent.key) &&
injectImportSpecifier
) {
return identifiers.concat(parent.parent.key as InjectedParameter);
return identifiers.concat(parentToCheck.parent.key as InjectedParameter);
}

return identifiers;
Expand Down

0 comments on commit d3e84d8

Please sign in to comment.