From d8d0aad34b76d75cd0b009a805020eea5be205c7 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Thu, 8 Feb 2024 22:23:08 +0900 Subject: [PATCH 1/3] fix(eslint-plugin): [no-var-requires, no-require-imports] support template literal --- .../src/rules/no-require-imports.ts | 30 +++++++++++-------- .../src/rules/no-var-requires.ts | 13 ++++---- .../tests/rules/no-require-imports.test.ts | 30 +++++++++++++++++++ .../tests/rules/no-var-requires.test.ts | 15 ++++++++++ 4 files changed, 71 insertions(+), 17 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-require-imports.ts b/packages/eslint-plugin/src/rules/no-require-imports.ts index 9b83ac66aeca..1956694484f4 100644 --- a/packages/eslint-plugin/src/rules/no-require-imports.ts +++ b/packages/eslint-plugin/src/rules/no-require-imports.ts @@ -42,16 +42,23 @@ export default util.createRule({ function isImportPathAllowed(importPath: string): boolean { return allowPatterns.some(pattern => importPath.match(pattern)); } + function isStringOrTemplateLiteral(node: TSESTree.Node): boolean { + return ( + (node.type === AST_NODE_TYPES.Literal && + typeof node.value === 'string') || + node.type === AST_NODE_TYPES.TemplateLiteral + ); + } + return { 'CallExpression[callee.name="require"]'( node: TSESTree.CallExpression, ): void { - if ( - node.arguments[0]?.type === AST_NODE_TYPES.Literal && - typeof node.arguments[0].value === 'string' && - isImportPathAllowed(node.arguments[0].value) - ) { - return; + if (node.arguments[0] && isStringOrTemplateLiteral(node.arguments[0])) { + const argValue = util.getStaticStringValue(node.arguments[0]); + if (typeof argValue === 'string' && isImportPathAllowed(argValue)) { + return; + } } const variable = ASTUtils.findVariable( context.sourceCode.getScope(node), @@ -68,12 +75,11 @@ export default util.createRule({ } }, TSExternalModuleReference(node): void { - if ( - node.expression.type === AST_NODE_TYPES.Literal && - typeof node.expression.value === 'string' && - isImportPathAllowed(node.expression.value) - ) { - return; + if (isStringOrTemplateLiteral(node.expression)) { + const argValue = util.getStaticStringValue(node.expression); + if (typeof argValue === 'string' && isImportPathAllowed(argValue)) { + return; + } } context.report({ node, diff --git a/packages/eslint-plugin/src/rules/no-var-requires.ts b/packages/eslint-plugin/src/rules/no-var-requires.ts index 30838ed7b99d..e77901886c8a 100644 --- a/packages/eslint-plugin/src/rules/no-var-requires.ts +++ b/packages/eslint-plugin/src/rules/no-var-requires.ts @@ -1,7 +1,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils'; -import { createRule } from '../util'; +import { createRule, getStaticStringValue } from '../util'; type Options = [ { @@ -48,11 +48,14 @@ export default createRule({ node: TSESTree.CallExpression, ): void { if ( - node.arguments[0]?.type === AST_NODE_TYPES.Literal && - typeof node.arguments[0].value === 'string' && - isImportPathAllowed(node.arguments[0].value) + (node.arguments[0]?.type === AST_NODE_TYPES.Literal && + typeof node.arguments[0].value === 'string') || + node.arguments[0]?.type === AST_NODE_TYPES.TemplateLiteral ) { - return; + const argValue = getStaticStringValue(node.arguments[0]); + if (typeof argValue === 'string' && isImportPathAllowed(argValue)) { + return; + } } const parent = node.parent.type === AST_NODE_TYPES.ChainExpression diff --git a/packages/eslint-plugin/tests/rules/no-require-imports.test.ts b/packages/eslint-plugin/tests/rules/no-require-imports.test.ts index 42374ccffbf8..bdfddbc25ae0 100644 --- a/packages/eslint-plugin/tests/rules/no-require-imports.test.ts +++ b/packages/eslint-plugin/tests/rules/no-require-imports.test.ts @@ -31,6 +31,10 @@ require('remark-preset-prettier'); code: "const pkg = require('../package.json');", options: [{ allow: ['/package\\.json$'] }], }, + { + code: 'const pkg = require(`./package.json`);', + options: [{ allow: ['/package\\.json$'] }], + }, { code: "const pkg = require('../packages/package.json');", options: [{ allow: ['/package\\.json$'] }], @@ -47,6 +51,10 @@ require('remark-preset-prettier'); code: "import pkg = require('some-package');", options: [{ allow: ['^some-package$'] }], }, + { + code: 'import pkg = require(`some-package`);', + options: [{ allow: ['^some-package$'] }], + }, ], invalid: [ { @@ -156,6 +164,17 @@ var lib5 = require?.('lib5'), }, ], }, + { + code: 'const pkg = require(`./package.jsonc`);', + options: [{ allow: ['/package\\.json$'] }], + errors: [ + { + line: 1, + column: 13, + messageId: 'noRequireImports', + }, + ], + }, { code: "import pkg = require('./package.json');", errors: [ @@ -188,5 +207,16 @@ var lib5 = require?.('lib5'), }, ], }, + { + code: 'import pkg = require(`./package.json`);', + options: [{ allow: ['^some-package$'] }], + errors: [ + { + line: 1, + column: 14, + messageId: 'noRequireImports', + }, + ], + }, ], }); diff --git a/packages/eslint-plugin/tests/rules/no-var-requires.test.ts b/packages/eslint-plugin/tests/rules/no-var-requires.test.ts index 718bcc46db31..2720475b3b8d 100644 --- a/packages/eslint-plugin/tests/rules/no-var-requires.test.ts +++ b/packages/eslint-plugin/tests/rules/no-var-requires.test.ts @@ -36,6 +36,10 @@ const json = require('./some.json'); code: "const pkg = require('some-package');", options: [{ allow: ['^some-package$'] }], }, + { + code: 'const pkg = require(`some-package`);', + options: [{ allow: ['^some-package$'] }], + }, ], invalid: [ { @@ -209,5 +213,16 @@ configValidator.addSchema(require('./a.json')); }, ], }, + { + code: 'const pkg = require(`./package.json`);', + options: [{ allow: ['^some-package$'] }], + errors: [ + { + line: 1, + column: 13, + messageId: 'noVarReqs', + }, + ], + }, ], }); From e38f8456b243c7c4e9b3b5cd176cee5b207b8382 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Thu, 8 Feb 2024 22:45:01 +0900 Subject: [PATCH 2/3] refactor --- packages/eslint-plugin/src/rules/no-var-requires.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-var-requires.ts b/packages/eslint-plugin/src/rules/no-var-requires.ts index e77901886c8a..34b8bd6e38ad 100644 --- a/packages/eslint-plugin/src/rules/no-var-requires.ts +++ b/packages/eslint-plugin/src/rules/no-var-requires.ts @@ -48,9 +48,10 @@ export default createRule({ node: TSESTree.CallExpression, ): void { if ( - (node.arguments[0]?.type === AST_NODE_TYPES.Literal && + node.arguments[0] && + ((node.arguments[0].type === AST_NODE_TYPES.Literal && typeof node.arguments[0].value === 'string') || - node.arguments[0]?.type === AST_NODE_TYPES.TemplateLiteral + node.arguments[0].type === AST_NODE_TYPES.TemplateLiteral) ) { const argValue = getStaticStringValue(node.arguments[0]); if (typeof argValue === 'string' && isImportPathAllowed(argValue)) { From c7f004801464a44880b32608893f8a3f7510e806 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Wed, 21 Feb 2024 00:13:46 +0900 Subject: [PATCH 3/3] refactor --- .../eslint-plugin/src/rules/no-var-requires.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-var-requires.ts b/packages/eslint-plugin/src/rules/no-var-requires.ts index 34b8bd6e38ad..9bb9fb7c1921 100644 --- a/packages/eslint-plugin/src/rules/no-var-requires.ts +++ b/packages/eslint-plugin/src/rules/no-var-requires.ts @@ -43,16 +43,20 @@ export default createRule({ function isImportPathAllowed(importPath: string): boolean { return allowPatterns.some(pattern => importPath.match(pattern)); } + + function isStringOrTemplateLiteral(node: TSESTree.Node): boolean { + return ( + (node.type === AST_NODE_TYPES.Literal && + typeof node.value === 'string') || + node.type === AST_NODE_TYPES.TemplateLiteral + ); + } + return { 'CallExpression[callee.name="require"]'( node: TSESTree.CallExpression, ): void { - if ( - node.arguments[0] && - ((node.arguments[0].type === AST_NODE_TYPES.Literal && - typeof node.arguments[0].value === 'string') || - node.arguments[0].type === AST_NODE_TYPES.TemplateLiteral) - ) { + if (node.arguments[0] && isStringOrTemplateLiteral(node.arguments[0])) { const argValue = getStaticStringValue(node.arguments[0]); if (typeof argValue === 'string' && isImportPathAllowed(argValue)) { return;