feat(linter): continue working on no_cycle (#2471)

This commit is contained in:
Boshen 2024-02-23 13:16:30 +08:00 committed by GitHub
parent 2628c97eda
commit 2714a32970
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 450 additions and 64 deletions

View file

@ -1,7 +1,9 @@
#![allow(clippy::cast_possible_truncation)]
use std::{
collections::HashSet,
path::{Path, PathBuf},
sync::Arc,
ffi::OsStr,
path::{Component, Path, PathBuf},
};
use oxc_diagnostics::{
@ -20,8 +22,27 @@ use crate::{context::LintContext, rule::Rule};
struct NoCycleDiagnostic(#[label] Span, String);
/// <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-cycle.md>
#[derive(Debug, Default, Clone)]
pub struct NoCycle;
#[derive(Debug, Clone)]
pub struct NoCycle {
/// maximum dependency depth to traverse
max_depth: u32,
/// ignore external modules
#[allow(unused)]
ignore_external: bool,
/// Allow cyclic dependency if there is at least one dynamic import in the chain
#[allow(unused)]
allow_unsafe_dynamic_cyclic_dependency: bool,
}
impl Default for NoCycle {
fn default() -> Self {
Self {
max_depth: u32::MAX,
ignore_external: false,
allow_unsafe_dynamic_cyclic_dependency: false,
}
}
}
declare_oxc_lint!(
/// ### What it does
@ -53,18 +74,37 @@ declare_oxc_lint!(
);
impl Rule for NoCycle {
fn from_configuration(value: serde_json::Value) -> Self {
let obj = value.get(0);
Self {
max_depth: obj
.and_then(|v| v.get("maxDepth"))
.and_then(serde_json::Value::as_number)
.and_then(serde_json::Number::as_u64)
.map_or(u32::MAX, |n| n as u32),
ignore_external: obj
.and_then(|v| v.get("ignoreExternal"))
.and_then(serde_json::Value::as_bool)
.unwrap_or_default(),
allow_unsafe_dynamic_cyclic_dependency: obj
.and_then(|v| v.get("allowUnsafeDynamicCyclicDependency"))
.and_then(serde_json::Value::as_bool)
.unwrap_or_default(),
}
}
fn run_once(&self, ctx: &LintContext<'_>) {
let module_record = ctx.semantic().module_record();
let mut visited: HashSet<PathBuf> = HashSet::new();
let mut stack: Vec<(Atom, PathBuf)> = Vec::new();
let needle = &module_record.resolved_absolute_path;
let cwd = std::env::current_dir().unwrap();
let needle = &module_record.resolved_absolute_path;
if visit(module_record, &mut visited, &mut stack, needle) {
let mut state = State::default();
if self.detect_cycle(&mut state, module_record, needle) {
let stack = &state.stack;
let span = module_record.requested_modules.get(&stack[0].0).unwrap()[0];
let help = stack
.into_iter()
.iter()
.map(|(specifier, path)| {
let path =
path.strip_prefix(&cwd).unwrap().to_string_lossy().replace('\\', "/");
@ -77,64 +117,198 @@ impl Rule for NoCycle {
}
}
/// Walks ModuleRecord and returns the path stack
/// if there is a cycle
fn visit(
module_record: &Arc<ModuleRecord>,
visited: &mut HashSet<PathBuf>,
stack: &mut Vec<(Atom, PathBuf)>,
needle: &Path,
) -> bool {
let path = &module_record.resolved_absolute_path;
if path.components().any(|c| match c {
std::path::Component::Normal(p) => p == std::ffi::OsStr::new("node_modules"),
_ => false,
}) {
return false;
#[derive(Debug, Default)]
struct State {
traversed: HashSet<PathBuf>,
stack: Vec<(Atom, PathBuf)>,
}
impl NoCycle {
fn detect_cycle(&self, state: &mut State, module_record: &ModuleRecord, needle: &Path) -> bool {
let path = &module_record.resolved_absolute_path;
if state.stack.len() as u32 > self.max_depth {
return false;
}
if path
.components()
.any(|c| matches!(c, Component::Normal(p) if p == OsStr::new("node_modules")))
{
return false;
}
for module_record_ref in &module_record.loaded_modules {
let resolved_absolute_path = &module_record_ref.resolved_absolute_path;
if !state.traversed.insert(resolved_absolute_path.clone()) {
continue;
}
state.stack.push((module_record_ref.key().clone(), resolved_absolute_path.clone()));
if needle == resolved_absolute_path {
return true;
}
if self.detect_cycle(state, module_record_ref.value(), needle) {
return true;
}
state.stack.pop();
}
false
}
for module_record_ref in &module_record.loaded_modules {
let resolved_absolute_path = &module_record_ref.resolved_absolute_path;
if !visited.insert(resolved_absolute_path.clone()) {
continue;
}
stack.push((module_record_ref.key().clone(), resolved_absolute_path.clone()));
if needle == resolved_absolute_path {
return true;
}
if visit(module_record_ref.value(), visited, stack, needle) {
return true;
}
stack.pop();
}
false
}
#[test]
fn test() {
use serde_json::json;
use crate::tester::Tester;
let pass = vec![
"import foo from './foo.js'",
"import _ from 'lodash'",
"import foo from '@scope/foo'",
"require('./foo')",
"require('../foo')",
"require('foo')",
"require('./')",
"require('@scope/foo')",
"require('./bar/index')",
"require('./bar')",
(r#"import foo from "./foo.js""#, None),
(r#"import _ from "lodash""#, None),
(r#"import foo from "@scope/foo""#, None),
(r#"var _ = require("lodash")"#, None),
(r#"var find = require("lodash.find")"#, None),
(r#"var foo = require("./foo")"#, None),
(r#"var foo = require("../foo")"#, None),
(r#"var foo = require("foo")"#, None),
(r#"var foo = require("./")"#, None),
(r#"var foo = require("@scope/foo")"#, None),
(r#"var bar = require("./bar/index")"#, None),
(r#"var bar = require("./bar")"#, None),
(r#"var bar = require("./bar")"#, None),
// TODO: settings 'import/external-module-folders': ['cycles/external'],
// (r#"import { foo } from "./external-depth-two""#, Some(json!([[{"ignoreExternal":true}]))),
// (
// r#"import { foo } from "cycles/external/depth-one""#,
// Some(json!([[{"ignoreExternal":true}])),
// ),
(r#"import { foo } from "./es6/depth-two""#, Some(json!([{"maxDepth":1}]))),
(r#"import { foo, bar } from "./es6/depth-two""#, Some(json!([{"maxDepth":1}]))),
(r#"import("./es6/depth-two").then(function({ foo }) {})"#, Some(json!([{"maxDepth":1}]))),
// parser: parsers.BABEL_OLD
// (r#"import type { FooType } from "./es6/depth-one""#, None),
// (r#"import type { FooType, BarType } from "./es6/depth-one""#, None),
(
r#"function bar(){ return import("./es6/depth-one"); } // #2265 1"#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import { foo } from "./es6/depth-one-dynamic"; // #2265 2"#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"function bar(){ return import("./es6/depth-one"); } // #2265 3"#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import { foo } from "./es6/depth-one-dynamic"; // #2265 4"#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
// Flow not supported
// (r#"import { bar } from "./flow-types""#, None),
// (r#"import { bar } from "./flow-types-only-importing-type""#, None),
// (r#"import { bar } from "./flow-types-only-importing-multiple-types""#, None),
// (r#"import { bar } from "./flow-typeof""#, None),
];
let fail = vec![
"import { foo } from './es6/depth-one'",
"const { foo } = require('./es6/depth-one')",
"import { foo } from './es6/depth-one-reexport'",
"import { foo } from './es6/depth-two'",
"import { foo } from './es6/depth-three-star'",
"import { foo } from './es6/depth-three-indirect'",
"import { foo } from './intermediate-ignore'",
"import { foo } from './ignore'",
// (r#"import { bar } from "./flow-types-some-type-imports""#, None),
// TODO: settings 'import/resolver': 'webpack', 'import/external-module-folders': ['cycles/external'],
// (r#"import { foo } from "cycles/external/depth-one""#, None),
// TODO: settings 'import/external-module-folders': ['cycles/external'],
// (r#"import { foo } from "./external-depth-two""#, None),
// (r#"import { foo } from "./es6/depth-one""#, None),
(r#"import { foo } from "./es6/depth-one""#, Some(json!([{"maxDepth":1}]))),
(r#"const { foo } = require("./es6/depth-one")"#, Some(json!([{"commonjs":true}]))),
// TODO: amd
// (r#"require(["./es6/depth-one"], d1 => {})"#, Some(json!([{"amd":true}]))),
// (r#"define(["./es6/depth-one"], d1 => {})"#, Some(json!([{"amd":true}]))),
(r#"import { foo } from "./es6/depth-one-reexport""#, None),
(r#"import { foo } from "./es6/depth-two""#, None),
(r#"import { foo } from "./es6/depth-two""#, Some(json!([{"maxDepth":2}]))),
(r#"const { foo } = require("./es6/depth-two")"#, Some(json!([{"commonjs":true}]))),
(r#"import { two } from "./es6/depth-three-star""#, None),
(r#"import one, { two, three } from "./es6/depth-three-star""#, None),
(r#"import { bar } from "./es6/depth-three-indirect""#, None),
(r#"import { bar } from "./es6/depth-three-indirect""#, None),
(r#"import { foo } from "./es6/depth-two""#, Some(json!([{"maxDepth":null}]))),
(r#"import { foo } from "./es6/depth-two""#, Some(json!([{"maxDepth":""}]))),
(
r#"import { foo } from "./es6/depth-one""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import { foo } from "./es6/depth-one""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true,"maxDepth":1}])),
),
(
r#"const { foo } = require("./es6/depth-one")"#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true,"commonjs":true}])),
),
// TODO: amd
// (
// r#"require(["./es6/depth-one"], d1 => {})"#,
// Some(json!([{"allowUnsafeDynamicCyclicDependency":true,"amd":true}])),
// ),
// (
// r#"define(["./es6/depth-one"], d1 => {})"#,
// Some(json!([{"allowUnsafeDynamicCyclicDependency":true,"amd":true}])),
// ),
(
r#"import { foo } from "./es6/depth-one-reexport""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import { foo } from "./es6/depth-two""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import { foo } from "./es6/depth-two""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true,"maxDepth":2}])),
),
(
r#"const { foo } = require("./es6/depth-two")"#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true,"commonjs":true}])),
),
(
r#"import { two } from "./es6/depth-three-star""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import one, { two, three } from "./es6/depth-three-star""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import { bar } from "./es6/depth-three-indirect""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import { bar } from "./es6/depth-three-indirect""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true}])),
),
(
r#"import { foo } from "./es6/depth-two""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true,"maxDepth":null}])),
),
(
r#"import { foo } from "./es6/depth-two""#,
Some(json!([{"allowUnsafeDynamicCyclicDependency":true,"maxDepth":""}])),
),
// TODO: dynamic import
// (r#"import("./es6/depth-three-star")"#, None),
// (r#"import("./es6/depth-three-indirect")"#, None),
(r#"import { foo } from "./es6/depth-two""#, Some(json!([{"maxDepth":null}]))),
(r#"import { foo } from "./es6/depth-two""#, Some(json!([{"maxDepth":""}]))),
// TODO: dynamic import
// (r#"function bar(){ return import("./es6/depth-one"); } // #2265 5"#, None),
// (r#"import { foo } from "./es6/depth-one-dynamic"; // #2265 6"#, None),
// (r#"function bar(){ return import("./es6/depth-one"); } // #2265 7"#, None),
// (r#"import { foo } from "./es6/depth-one-dynamic"; // #2265 8"#, None),
// // Flow not supported
// (r#"import { bar } from "./flow-types-depth-one""#, None),
(r#"import { foo } from "./intermediate-ignore""#, None),
(r#"import { foo } from "./ignore""#, None),
];
Tester::new(NoCycle::NAME, pass, fail)

View file

@ -5,7 +5,7 @@ expression: no_cycle
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from './es6/depth-one'
1 │ import { foo } from "./es6/depth-one"
· ─────────────────
╰────
help: These paths form a cycle:
@ -14,7 +14,7 @@ expression: no_cycle
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:25]
1 │ const { foo } = require('./es6/depth-one')
1 │ const { foo } = require("./es6/depth-one")
· ─────────────────
╰────
help: These paths form a cycle:
@ -23,7 +23,7 @@ expression: no_cycle
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from './es6/depth-one-reexport'
1 │ import { foo } from "./es6/depth-one-reexport"
· ──────────────────────────
╰────
help: These paths form a cycle:
@ -32,7 +32,7 @@ expression: no_cycle
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from './es6/depth-two'
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
@ -42,7 +42,27 @@ expression: no_cycle
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from './es6/depth-three-star'
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:25]
1 │ const { foo } = require("./es6/depth-two")
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { two } from "./es6/depth-three-star"
· ────────────────────────
╰────
help: These paths form a cycle:
@ -51,9 +71,20 @@ expression: no_cycle
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:33]
1 │ import one, { two, three } from "./es6/depth-three-star"
· ────────────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-three-star - fixtures/import/cycles/es6/depth-three-star.js
-> ./depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from './es6/depth-three-indirect'
1 │ import { bar } from "./es6/depth-three-indirect"
· ────────────────────────────
╰────
help: These paths form a cycle:
@ -64,7 +95,188 @@ expression: no_cycle
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from './intermediate-ignore'
1 │ import { bar } from "./es6/depth-three-indirect"
· ────────────────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-three-indirect - fixtures/import/cycles/es6/depth-three-indirect.js
-> ./depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-one"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-one"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:25]
1 │ const { foo } = require("./es6/depth-one")
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-one-reexport"
· ──────────────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-one-reexport - fixtures/import/cycles/es6/depth-one-reexport.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:25]
1 │ const { foo } = require("./es6/depth-two")
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { two } from "./es6/depth-three-star"
· ────────────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-three-star - fixtures/import/cycles/es6/depth-three-star.js
-> ./depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:33]
1 │ import one, { two, three } from "./es6/depth-three-star"
· ────────────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-three-star - fixtures/import/cycles/es6/depth-three-star.js
-> ./depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { bar } from "./es6/depth-three-indirect"
· ────────────────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-three-indirect - fixtures/import/cycles/es6/depth-three-indirect.js
-> ./depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { bar } from "./es6/depth-three-indirect"
· ────────────────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-three-indirect - fixtures/import/cycles/es6/depth-three-indirect.js
-> ./depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./es6/depth-two"
· ─────────────────
╰────
help: These paths form a cycle:
-> ./es6/depth-two - fixtures/import/cycles/es6/depth-two.js
-> ./depth-one - fixtures/import/cycles/es6/depth-one.js
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from "./intermediate-ignore"
· ───────────────────────
╰────
help: These paths form a cycle:
@ -74,7 +286,7 @@ expression: no_cycle
⚠ eslint-plugin-import(no-cycle): Dependency cycle detected
╭─[cycles/depth-zero.js:1:21]
1 │ import { foo } from './ignore'
1 │ import { foo } from "./ignore"
· ──────────
╰────
help: These paths form a cycle: