Repository: import-js/eslint-plugin-import
Pull request #1223 (2018-10-26 03:45:41)

[New] `no-dynamic-require`: add option `esmodule`
Requested in [#700](https://github.com/benmosher/eslint-plugin-import/issues/700#issuecomment-268881937).

Adds an option `esmodule` to `no-dynamic-require` that defaults to false.

I think it'd be nice if `no-dynamic-require` was renamed to something like `no-nonliteral-import`, since it is confusing with `import()` being called "dynamic import".


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53cc7824..41799fb6 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 0c14df08..f8900088 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',
+          });
+        }
       },
     };
   },


Test patch:
diff --git a/tests/src/rules/no-dynamic-require.js b/tests/src/rules/no-dynamic-require.js
index 7dba2423..4a70e7bc 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}`)',