diff --git a/src/rules/no-cycle.js b/src/rules/no-cycle.js index d256b216f1..0aa3626827 100644 --- a/src/rules/no-cycle.js +++ b/src/rules/no-cycle.js @@ -58,7 +58,10 @@ module.exports = { return; // ignore external modules } if (options.allowUnsafeDynamicCyclicDependency && ( - importer.type === 'ImportExpression' || importer.type === 'CallExpression')) { + // Ignore `import()` + importer.type === 'ImportExpression' || + // `require()` calls are always checked (if possible) + (importer.type === 'CallExpression' && importer.callee.name !== 'require'))) { return; // cycle via dynamic import allowed by config } diff --git a/tests/src/rules/no-cycle.js b/tests/src/rules/no-cycle.js index 22df52bc74..d93b94c8bf 100644 --- a/tests/src/rules/no-cycle.js +++ b/tests/src/rules/no-cycle.js @@ -136,104 +136,117 @@ ruleTester.run('no-cycle', rule, { }, }), - flatMap(testDialects, (testDialect) => [ - test({ - code: `import { foo } from "./${testDialect}/depth-one"`, - errors: [error(`Dependency cycle detected.`)], - }), - test({ - code: `import { foo } from "./${testDialect}/depth-one"`, - options: [{ maxDepth: 1 }], - errors: [error(`Dependency cycle detected.`)], - }), - test({ - code: `const { foo } = require("./${testDialect}/depth-one")`, - errors: [error(`Dependency cycle detected.`)], - options: [{ commonjs: true }], - }), - test({ - code: `require(["./${testDialect}/depth-one"], d1 => {})`, - errors: [error(`Dependency cycle detected.`)], - options: [{ amd: true }], - }), - test({ - code: `define(["./${testDialect}/depth-one"], d1 => {})`, - errors: [error(`Dependency cycle detected.`)], - options: [{ amd: true }], - }), - test({ - code: `import { foo } from "./${testDialect}/depth-two"`, - errors: [error(`Dependency cycle via ./depth-one:1`)], - }), - test({ - code: `import { foo } from "./${testDialect}/depth-two"`, - options: [{ maxDepth: 2 }], - errors: [error(`Dependency cycle via ./depth-one:1`)], - }), - test({ - code: `const { foo } = require("./${testDialect}/depth-two")`, - errors: [error(`Dependency cycle via ./depth-one:1`)], - options: [{ commonjs: true }], - }), - test({ - code: `import { two } from "./${testDialect}/depth-three-star"`, - errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], - }), - test({ - code: `import one, { two, three } from "./${testDialect}/depth-three-star"`, - errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], - }), - test({ - code: `import { bar } from "./${testDialect}/depth-three-indirect"`, - errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], - }), - test({ - code: `import { bar } from "./${testDialect}/depth-three-indirect"`, - errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], - parser: parsers.BABEL_OLD, - }), - test({ - code: `import("./${testDialect}/depth-three-star")`, - errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], - parser: parsers.BABEL_OLD, - }), - test({ - code: `import("./${testDialect}/depth-three-indirect")`, - errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], - parser: parsers.BABEL_OLD, - }), - test({ - code: `import { foo } from "./${testDialect}/depth-two"`, - options: [{ maxDepth: Infinity }], - errors: [error(`Dependency cycle via ./depth-one:1`)], - }), - test({ - code: `import { foo } from "./${testDialect}/depth-two"`, - options: [{ maxDepth: '∞' }], - errors: [error(`Dependency cycle via ./depth-one:1`)], - }), - test({ - code: `function bar(){ return import("./${testDialect}/depth-one"); } // #2265 5`, - errors: [error(`Dependency cycle detected.`)], - parser: parsers.BABEL_OLD, - }), - testVersion('> 3', () => ({ // Dynamic import is not properly caracterized with eslint < 4 - code: `import { foo } from "./${testDialect}/depth-one-dynamic"; // #2265 6`, - errors: [error(`Dependency cycle detected.`)], - parser: parsers.BABEL_OLD, - })), - ].concat(parsers.TS_NEW ? [ - test({ - code: `function bar(){ return import("./${testDialect}/depth-one"); } // #2265 7`, - errors: [error(`Dependency cycle detected.`)], - parser: parsers.TS_NEW, - }), - test({ - code: `import { foo } from "./${testDialect}/depth-one-dynamic"; // #2265 8`, - errors: [error(`Dependency cycle detected.`)], - parser: parsers.TS_NEW, - }), - ] : [])), + flatMap(testDialects, (testDialect) => + // Ensure behavior does not change for those tests, with or without ` + flatMap([ + {}, + { allowUnsafeDynamicCyclicDependency: true }, + ], (opts) => [ + test({ + code: `import { foo } from "./${testDialect}/depth-one"`, + options: [{ ...opts }], + errors: [error(`Dependency cycle detected.`)], + }), + test({ + code: `import { foo } from "./${testDialect}/depth-one"`, + options: [{ ...opts, maxDepth: 1 }], + errors: [error(`Dependency cycle detected.`)], + }), + test({ + code: `const { foo } = require("./${testDialect}/depth-one")`, + errors: [error(`Dependency cycle detected.`)], + options: [{ ...opts, commonjs: true }], + }), + test({ + code: `require(["./${testDialect}/depth-one"], d1 => {})`, + errors: [error(`Dependency cycle detected.`)], + options: [{ ...opts, amd: true }], + }), + test({ + code: `define(["./${testDialect}/depth-one"], d1 => {})`, + errors: [error(`Dependency cycle detected.`)], + options: [{ ...opts, amd: true }], + }), + test({ + code: `import { foo } from "./${testDialect}/depth-two"`, + options: [{ ...opts }], + errors: [error(`Dependency cycle via ./depth-one:1`)], + }), + test({ + code: `import { foo } from "./${testDialect}/depth-two"`, + options: [{ ...opts, maxDepth: 2 }], + errors: [error(`Dependency cycle via ./depth-one:1`)], + }), + test({ + code: `const { foo } = require("./${testDialect}/depth-two")`, + errors: [error(`Dependency cycle via ./depth-one:1`)], + options: [{ ...opts, commonjs: true }], + }), + test({ + code: `import { two } from "./${testDialect}/depth-three-star"`, + options: [{ ...opts }], + errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], + }), + test({ + code: `import one, { two, three } from "./${testDialect}/depth-three-star"`, + options: [{ ...opts }], + errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], + }), + test({ + code: `import { bar } from "./${testDialect}/depth-three-indirect"`, + options: [{ ...opts }], + errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], + }), + test({ + code: `import { bar } from "./${testDialect}/depth-three-indirect"`, + options: [{ ...opts }], + errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], + parser: parsers.BABEL_OLD, + }), + test({ + code: `import { foo } from "./${testDialect}/depth-two"`, + options: [{ ...opts, maxDepth: Infinity }], + errors: [error(`Dependency cycle via ./depth-one:1`)], + }), + test({ + code: `import { foo } from "./${testDialect}/depth-two"`, + options: [{ ...opts, maxDepth: '∞' }], + errors: [error(`Dependency cycle via ./depth-one:1`)], + }), + ]).concat([ + test({ + code: `import("./${testDialect}/depth-three-star")`, + errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], + parser: parsers.BABEL_OLD, + }), + test({ + code: `import("./${testDialect}/depth-three-indirect")`, + errors: [error(`Dependency cycle via ./depth-two:1=>./depth-one:1`)], + parser: parsers.BABEL_OLD, + }), + test({ + code: `function bar(){ return import("./${testDialect}/depth-one"); } // #2265 5`, + errors: [error(`Dependency cycle detected.`)], + parser: parsers.BABEL_OLD, + }), + ]).concat( + testVersion('> 3', () => ({ // Dynamic import is not properly caracterized with eslint < 4 + code: `import { foo } from "./${testDialect}/depth-one-dynamic"; // #2265 6`, + errors: [error(`Dependency cycle detected.`)], + parser: parsers.BABEL_OLD, + })), + ).concat(parsers.TS_NEW ? [ + test({ + code: `function bar(){ return import("./${testDialect}/depth-one"); } // #2265 7`, + errors: [error(`Dependency cycle detected.`)], + parser: parsers.TS_NEW, + }), + test({ + code: `import { foo } from "./${testDialect}/depth-one-dynamic"; // #2265 8`, + errors: [error(`Dependency cycle detected.`)], + parser: parsers.TS_NEW, + }), + ] : [])), test({ code: 'import { bar } from "./flow-types-depth-one"',