From 95e1f467e78c07ec31f47cf289ef4153d6ba2641 Mon Sep 17 00:00:00 2001 From: Victor <106590915+victor-diez-sonarsource@users.noreply.github.com> Date: Wed, 25 Jan 2023 11:43:36 +0100 Subject: [PATCH] Add support for `import = require` (#3665) --- .../linting/eslint/rules/helpers/module.ts | 69 +++++++++++++++++-- .../eslint/rules/helpers/aws/cdk.test.ts | 23 +++++++ 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/eslint-bridge/src/linting/eslint/rules/helpers/module.ts b/eslint-bridge/src/linting/eslint/rules/helpers/module.ts index 958a7e4978a..a71c4bb7f66 100644 --- a/eslint-bridge/src/linting/eslint/rules/helpers/module.ts +++ b/eslint-bridge/src/linting/eslint/rules/helpers/module.ts @@ -160,7 +160,29 @@ export function getFullyQualifiedNameRaw( if (!definition) { return null; } + // imports + const fqnFromImport = checkFqnFromImport(variable, definition, context, fqn, visitedVars); + if (fqnFromImport !== null) { + return fqnFromImport; + } + + // requires + const fqnFromRequire = checkFqnFromRequire(variable, definition, context, fqn, visitedVars); + if (fqnFromRequire !== null) { + return fqnFromRequire; + } + + return null; +} + +function checkFqnFromImport( + variable: Scope.Variable, + definition: Scope.Definition, + context: Rule.RuleContext, + fqn: string[], + visitedVars: Variable[], +) { if (definition.type === 'ImportBinding') { const specifier = definition.node; const importDeclaration = definition.parent; @@ -175,8 +197,42 @@ export function getFullyQualifiedNameRaw( fqn.unshift(...importedQualifiers); return fqn.join('.'); } + // import s3 = require('aws-cdk-lib/aws-s3'); + if ((importDeclaration as TSESTree.Node).type === 'TSImportEqualsDeclaration') { + const importedModule = (importDeclaration as unknown as TSESTree.TSImportEqualsDeclaration) + .moduleReference; + if ( + importedModule.type === 'TSExternalModuleReference' && + importedModule.expression.type === 'Literal' && + typeof importedModule.expression.value === 'string' + ) { + const importedQualifiers = importedModule.expression.value.split('/'); + fqn.unshift(...importedQualifiers); + return fqn.join('.'); + } + //import s3 = cdk.aws_s3; + if (importedModule.type === 'TSQualifiedName') { + visitedVars.push(variable); + return getFullyQualifiedNameRaw( + context, + importedModule as unknown as estree.Node, + fqn, + variable.scope, + visitedVars, + ); + } + } } + return null; +} +function checkFqnFromRequire( + variable: Scope.Variable, + definition: Scope.Definition, + context: Rule.RuleContext, + fqn: string[], + visitedVars: Variable[], +) { const value = getUniqueWriteReference(variable); // requires if (definition.type === 'Variable' && value) { @@ -196,13 +252,8 @@ export function getFullyQualifiedNameRaw( fqn.unshift(...importedQualifiers); return fqn.join('.'); } else { - return getFullyQualifiedNameRaw( - context, - nodeToCheck, - fqn, - variable.scope, - visitedVars.concat(variable), - ); + visitedVars.push(variable); + return getFullyQualifiedNameRaw(context, nodeToCheck, fqn, variable.scope, visitedVars); } } return null; @@ -273,6 +324,10 @@ export function reduceTo( // we should migrate to use only TSESTree types everywhere to avoid casting nodeToCheck = (nodeToCheck as unknown as TSESTree.TSNonNullExpression) .expression as estree.Expression; + } else if ((nodeToCheck as TSESTree.Node).type === 'TSQualifiedName') { + const qualified = nodeToCheck as unknown as TSESTree.TSQualifiedName; + fqn.unshift(qualified.right.name); + nodeToCheck = qualified.left as estree.Node; } else { break; } diff --git a/eslint-bridge/tests/linting/eslint/rules/helpers/aws/cdk.test.ts b/eslint-bridge/tests/linting/eslint/rules/helpers/aws/cdk.test.ts index abe196c9a08..3ecbdc7f95f 100644 --- a/eslint-bridge/tests/linting/eslint/rules/helpers/aws/cdk.test.ts +++ b/eslint-bridge/tests/linting/eslint/rules/helpers/aws/cdk.test.ts @@ -60,6 +60,14 @@ import { default as cdk } from 'aws-cdk-lib'; new cdk.aws_module.Class(...args); `, }, + { + code: ` +const awsCdk = 'aws-cdk-lib'; +import cdk = require(awsCdk); // FN +import module = cdk.aws_module; +new module.Class(); + `, + }, ], invalid: [ { @@ -204,6 +212,21 @@ new cdk.aws_module!.Class(); }, { code: ` +import cdk = require('aws-cdk-lib'); +new cdk.aws_module.Class(); + `, + errors: 1, + }, + { + code: ` +import cdk = require('aws-cdk-lib'); +import module = cdk.aws_module; +new module.Class(); + `, + errors: 1, + }, + { + code: ` import * as cdk from 'aws-cdk-lib'; new cdk.aws_module.Class(); `,