diff --git a/CHANGELOG.md b/CHANGELOG.md index 53cc78240..41799fb6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## [Unreleased] +### Added +- [`no-dynamic-require`]: add option `esmodule` ([#1223], thanks [@vikr01]) + ### Fixed - [`no-duplicates`]: ensure autofix avoids excessive newlines ([#2028], thanks [@ertrzyiks]) - [`extensions`]: avoid crashing on partially typed import/export statements ([#2118], thanks [@ljharb]) @@ -888,6 +891,7 @@ for info on changes for earlier releases. [#1619]: https://github.com/benmosher/eslint-plugin-import/pull/1619 [#1612]: https://github.com/benmosher/eslint-plugin-import/pull/1612 [#1611]: https://github.com/benmosher/eslint-plugin-import/pull/1611 +[#1223]: https://github.com/benmosher/eslint-plugin-import/pull/1223 [#1605]: https://github.com/benmosher/eslint-plugin-import/pull/1605 [#1586]: https://github.com/benmosher/eslint-plugin-import/pull/1586 [#1572]: https://github.com/benmosher/eslint-plugin-import/pull/1572 diff --git a/src/rules/no-dynamic-require.js b/src/rules/no-dynamic-require.js index 0c14df089..f8900088d 100644 --- a/src/rules/no-dynamic-require.js +++ b/src/rules/no-dynamic-require.js @@ -8,6 +8,12 @@ function isRequire(node) { node.arguments.length >= 1; } +function isDynamicImport(node) { + return node && + node.callee && + node.callee.type === 'Import'; +} + function isStaticValue(arg) { return arg.type === 'Literal' || (arg.type === 'TemplateLiteral' && arg.expressions.length === 0); @@ -19,18 +25,39 @@ module.exports = { docs: { url: docsUrl('no-dynamic-require'), }, - schema: [], + schema: [ + { + type: 'object', + properties: { + esmodule: { + type: 'boolean', + }, + }, + additionalProperties: false, + }, + ], }, create: function (context) { + const options = context.options[0] || {}; + return { CallExpression(node) { - if (isRequire(node) && !isStaticValue(node.arguments[0])) { - context.report({ + if (!node.arguments[0] || isStaticValue(node.arguments[0])) { + return; + } + if (isRequire(node)) { + return context.report({ node, message: 'Calls to require() should use string literals', }); } + if (options.esmodule && isDynamicImport(node)) { + return context.report({ + node, + message: 'Calls to import() should use string literals', + }); + } }, }; }, diff --git a/tests/src/rules/no-dynamic-require.js b/tests/src/rules/no-dynamic-require.js index 7dba24231..4a70e7bc2 100644 --- a/tests/src/rules/no-dynamic-require.js +++ b/tests/src/rules/no-dynamic-require.js @@ -9,6 +9,10 @@ const error = { message: 'Calls to require() should use string literals', }; +const dynamicImportError = { + message: 'Calls to import() should use string literals', +}; + ruleTester.run('no-dynamic-require', rule, { valid: [ test({ code: 'import _ from "lodash"' }), @@ -22,6 +26,59 @@ ruleTester.run('no-dynamic-require', rule, { test({ code: 'var foo = require(`foo`)' }), test({ code: 'var foo = require("./foo")' }), test({ code: 'var foo = require("@scope/foo")' }), + + //dynamic import + test({ + code: 'import("foo")', + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'import(`foo`)', + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'import("./foo")', + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'import("@scope/foo")', + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'var foo = import("foo")', + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'var foo = import(`foo`)', + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'var foo = import("./foo")', + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'var foo = import("@scope/foo")', + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'import("../" + name)', + errors: [dynamicImportError], + parser: require.resolve('babel-eslint'), + options: [{ esmodule: false }], + }), + test({ + code: 'import(`../${name}`)', + errors: [dynamicImportError], + parser: require.resolve('babel-eslint'), + }), ], invalid: [ test({ @@ -43,6 +100,33 @@ ruleTester.run('no-dynamic-require', rule, { test({ code: 'require(name + "foo", "bar")', errors: [error], + options: [{ esmodule: true }], + }), + + // dynamic import + test({ + code: 'import("../" + name)', + errors: [dynamicImportError], + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'import(`../${name}`)', + errors: [dynamicImportError], + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'import(name)', + errors: [dynamicImportError], + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], + }), + test({ + code: 'import(name())', + errors: [dynamicImportError], + parser: require.resolve('babel-eslint'), + options: [{ esmodule: true }], }), test({ code: 'require(`foo${x}`)',