diff --git a/.changeset/some-badgers-move.md b/.changeset/some-badgers-move.md new file mode 100644 index 000000000000..3a4d22cb3faf --- /dev/null +++ b/.changeset/some-badgers-move.md @@ -0,0 +1,5 @@ +--- +"@biomejs/biome": patch +--- + +Improved performance for [`noImportCycles`](https://biomejs.dev/linter/rules/no-import-cycles/) by explicitly excluding node_modules from the cycle detection. The performance improvement is directly proportional to how big your dependency tree is. diff --git a/crates/biome_js_analyze/src/lint/suspicious/no_import_cycles.rs b/crates/biome_js_analyze/src/lint/suspicious/no_import_cycles.rs index b8ddc1706939..b100d4b3d2f0 100644 --- a/crates/biome_js_analyze/src/lint/suspicious/no_import_cycles.rs +++ b/crates/biome_js_analyze/src/lint/suspicious/no_import_cycles.rs @@ -179,6 +179,12 @@ impl Rule for NoImportCycles { } let resolved_path = resolved_path.as_path()?; + + // Don't check for cycles through node_modules imports. + if is_node_modules_path(resolved_path) { + return None; + } + let imports = ctx.module_info_for_path(resolved_path)?; find_cycle(ctx, resolved_path, imports) @@ -252,6 +258,11 @@ fn find_cycle( continue; }; + // Skip node_modules paths — we don't traverse into dependencies. + if is_node_modules_path(path) { + continue; + } + if !seen.insert(resolved_path.clone()) { continue; } @@ -295,3 +306,8 @@ fn find_cycle( None } + +/// Returns `true` if the given path is inside a `node_modules` directory. +fn is_node_modules_path(path: &Utf8Path) -> bool { + path.components().any(|c| c.as_str() == "node_modules") +}