From f10447b8d30c41d17c2fed3f9fa1966fa0b67b6b Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Wed, 28 Aug 2024 19:00:49 +0200 Subject: [PATCH] 117616: Fixed alias-imports edge case where duplicate imports with different aliases were both kept --- lint/src/rules/ts/alias-imports.ts | 36 +++++++++++++++++++++++++----- lint/src/util/structure.ts | 4 ++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/lint/src/rules/ts/alias-imports.ts b/lint/src/rules/ts/alias-imports.ts index 2b16bb26bd..64b25f4c5a 100644 --- a/lint/src/rules/ts/alias-imports.ts +++ b/lint/src/rules/ts/alias-imports.ts @@ -1,4 +1,5 @@ import { + AST_NODE_TYPES, ESLintUtils, TSESLint, TSESTree, @@ -12,9 +13,16 @@ import { export enum Message { NO_ALIAS = 'noAlias', WRONG_ALIAS = 'wrongAlias', + MULTIPLE_ALIASES = 'multipleAliases', } -export const info: DSpaceESLintRuleInfo = { +interface AliasImportOption { + package: string; + imported: string; + local: string; +} + +export const info: DSpaceESLintRuleInfo<[[AliasImportOption]]> = { name: 'alias-imports', meta: { docs: { @@ -23,6 +31,7 @@ export const info: DSpaceESLintRuleInfo = { messages: { [Message.NO_ALIAS]: 'This import must be aliased', [Message.WRONG_ALIAS]: 'This import uses the wrong alias (should be {{ local }})', + [Message.MULTIPLE_ALIASES]: 'This import was used twice with a different alias (should be {{ local }})', }, fixable: 'code', type: 'problem', @@ -54,7 +63,7 @@ export const info: DSpaceESLintRuleInfo = { export const rule = ESLintUtils.RuleCreator.withoutDocs({ ...info, create(context: TSESLint.RuleContext, options: any) { - return options[0].reduce((selectors: any, option: any) => { + return options[0].reduce((selectors: any, option: AliasImportOption) => { selectors[`ImportDeclaration[source.value = "${option.package}"] > ImportSpecifier[imported.name = "${option.imported}"][local.name != "${option.local}"]`] = (node: TSESTree.ImportSpecifier) => handleUnaliasedImport(context, option, node); return selectors; }, {}); @@ -107,11 +116,28 @@ import { of as observableOf } from 'rxjs'; * Replaces the incorrectly aliased imports with the ones defined in the defaultOptions * * @param context The current {@link TSESLint.RuleContext} - * @param option The current `defaultOptions` that needs to be handled + * @param option The current {@link AliasImportOption} that needs to be handled * @param node The incorrect import node that should be fixed */ -function handleUnaliasedImport(context: TSESLint.RuleContext, option: any, node: TSESTree.ImportSpecifier): void { - if (node.local.name === node.imported.name) { +function handleUnaliasedImport(context: TSESLint.RuleContext, option: AliasImportOption, node: TSESTree.ImportSpecifier): void { + const hasAliasedImport: boolean = (node.parent as TSESTree.ImportDeclaration).specifiers.find((specifier: TSESTree.ImportClause) => specifier.local.name === option.local && specifier.type === AST_NODE_TYPES.ImportSpecifier && (specifier as TSESTree.ImportSpecifier).imported.name === option.imported) !== undefined; + + if (hasAliasedImport) { + context.report({ + messageId: Message.MULTIPLE_ALIASES, + node: node, + fix(fixer: TSESLint.RuleFixer) { + const commaAfter = context.sourceCode.getTokenAfter(node, { + filter: (token: TSESTree.Token) => token.value === ',', + }); + if (commaAfter) { + return fixer.removeRange([node.range[0], commaAfter.range[1]]); + } else { + return fixer.remove(node); + } + }, + }); + } else if (node.local.name === node.imported.name) { context.report({ messageId: Message.NO_ALIAS, node: node, diff --git a/lint/src/util/structure.ts b/lint/src/util/structure.ts index 2e3aebd9ab..326ce93cf6 100644 --- a/lint/src/util/structure.ts +++ b/lint/src/util/structure.ts @@ -17,10 +17,10 @@ export type Meta = RuleMetaData; export type Valid = ValidTestCase; export type Invalid = InvalidTestCase; -export interface DSpaceESLintRuleInfo { +export interface DSpaceESLintRuleInfo { name: string; meta: Meta, - defaultOptions: unknown[], + defaultOptions: T, } export interface NamedTests {