From 84ca374d102a3ed687b0b1bb05259afc66385a77 Mon Sep 17 00:00:00 2001 From: Boshen Date: Sun, 24 May 2026 22:36:04 +0800 Subject: [PATCH] fix(tsconfig): let project references take priority over their parent Align with TypeScript's `isSourceOfProjectReferenceRedirect`: when a parent tsconfig has `references`, a referenced sub-project that includes the file always wins, even when the parent's `include` / default `**/*` also covers it. Previously the parent claimed ownership first and references were only consulted as a fallback, so a solution-style root (only `references`, no `include` / `files`) hid the referenced sub-project's `compilerOptions.paths`. Closes #1086. --- .../project-references-priority/app/index.ts | 3 +++ .../cases/project-references-priority/lib/foo.ts | 1 + .../tsconfig.app.json | 10 ++++++++++ .../project-references-priority/tsconfig.json | 3 +++ src/tests/tsconfck.rs | 4 ++-- src/tests/tsconfig_project_references.rs | 16 ++++++++++++++++ src/tsconfig.rs | 1 - 7 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 fixtures/tsconfig/cases/project-references-priority/app/index.ts create mode 100644 fixtures/tsconfig/cases/project-references-priority/lib/foo.ts create mode 100644 fixtures/tsconfig/cases/project-references-priority/tsconfig.app.json create mode 100644 fixtures/tsconfig/cases/project-references-priority/tsconfig.json diff --git a/fixtures/tsconfig/cases/project-references-priority/app/index.ts b/fixtures/tsconfig/cases/project-references-priority/app/index.ts new file mode 100644 index 000000000..794bd4f76 --- /dev/null +++ b/fixtures/tsconfig/cases/project-references-priority/app/index.ts @@ -0,0 +1,3 @@ +import { foo } from "1/foo"; + +foo(); diff --git a/fixtures/tsconfig/cases/project-references-priority/lib/foo.ts b/fixtures/tsconfig/cases/project-references-priority/lib/foo.ts new file mode 100644 index 000000000..f99d42777 --- /dev/null +++ b/fixtures/tsconfig/cases/project-references-priority/lib/foo.ts @@ -0,0 +1 @@ +export function foo() {} diff --git a/fixtures/tsconfig/cases/project-references-priority/tsconfig.app.json b/fixtures/tsconfig/cases/project-references-priority/tsconfig.app.json new file mode 100644 index 000000000..07de83ec7 --- /dev/null +++ b/fixtures/tsconfig/cases/project-references-priority/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "moduleResolution": "bundler", + "paths": { + "1/*": ["./lib/*"] + } + }, + "include": ["app", "lib"] +} diff --git a/fixtures/tsconfig/cases/project-references-priority/tsconfig.json b/fixtures/tsconfig/cases/project-references-priority/tsconfig.json new file mode 100644 index 000000000..e295d7ac4 --- /dev/null +++ b/fixtures/tsconfig/cases/project-references-priority/tsconfig.json @@ -0,0 +1,3 @@ +{ + "references": [{ "path": "./tsconfig.app.json" }] +} diff --git a/src/tests/tsconfck.rs b/src/tests/tsconfck.rs index 5e941357a..1b6dda791 100644 --- a/src/tests/tsconfck.rs +++ b/src/tests/tsconfck.rs @@ -65,8 +65,8 @@ fn part_of_solution() { ("mixed", "src/baz.cts", "tsconfig.src.json"), ("mixed", "src/foo.ts", "tsconfig.src.json"), ("mixed", "src/foo.spec.ts", "tsconfig.test.json"), - ("referenced-extends-original", "src/foo.ts", "tsconfig.json"), - ("referenced-extends-original", "tests/foo.test.ts", "tsconfig.json"), + ("referenced-extends-original", "src/foo.ts", "src/tsconfig.src.json"), + ("referenced-extends-original", "tests/foo.test.ts", "tests/tsconfig.test.json"), ("referenced-with-configDir", "src/foo.ts", "tsconfig.src.json"), ( "referenced-with-configDir-and-extends", diff --git a/src/tests/tsconfig_project_references.rs b/src/tests/tsconfig_project_references.rs index d067231cf..a57c257ad 100644 --- a/src/tests/tsconfig_project_references.rs +++ b/src/tests/tsconfig_project_references.rs @@ -152,3 +152,19 @@ fn references_with_extends() { assert_eq!(resolved_path, Ok(f.join("src/pages/index.tsx"))); } + +#[test] +fn referenced_paths_win_over_root_with_no_paths() { + let f = super::fixture_root().join("tsconfig/cases/project-references-priority"); + + let resolver = Resolver::new(ResolveOptions { + extensions: vec![".ts".into()], + tsconfig: Some(TsconfigDiscovery::Auto), + ..ResolveOptions::default() + }); + + let resolved_path = + resolver.resolve_file(f.join("app/index.ts"), "1/foo").map(|f| f.full_path()); + + assert_eq!(resolved_path, Ok(f.join("lib/foo.ts"))); +} diff --git a/src/tsconfig.rs b/src/tsconfig.rs index 168eb9a9f..a219c3a6d 100644 --- a/src/tsconfig.rs +++ b/src/tsconfig.rs @@ -551,7 +551,6 @@ impl TsConfig { pub(crate) fn resolve_tsconfig_solution(tsconfig: Arc, path: &Path) -> Arc { if !tsconfig.references_resolved.is_empty() && tsconfig.is_file_extension_allowed_in_tsconfig(path) - && !tsconfig.is_file_included_in_tsconfig(path) && let Some(solution_tsconfig) = tsconfig .references_resolved .iter()