From 3516cebcb1144dcf6f07cb62866d48150ad4f264 Mon Sep 17 00:00:00 2001 From: cluezhang Date: Wed, 21 Aug 2024 19:37:25 +0800 Subject: [PATCH] fix(compiler-sfc): skip circular tsconfig project reference (#11382) --- .../compileScript/resolveType.spec.ts | 43 +++++++++++++++++++ .../compiler-sfc/src/script/resolveType.ts | 7 ++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts index ff33882568e..816d74bc649 100644 --- a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts @@ -1185,6 +1185,49 @@ describe('resolveType', () => { expect(deps && [...deps]).toStrictEqual(['/user.ts']) }) + // #11382 + test('ts module resolve circular project reference', () => { + const files = { + '/tsconfig.json': JSON.stringify({ + exclude: ['**/*.ts', '**/*.vue'], + references: [ + { + path: './tsconfig.web.json', + }, + ], + }), + '/tsconfig.web.json': JSON.stringify({ + include: ['**/*.ts', '**/*.vue'], + compilerOptions: { + composite: true, + paths: { + user: ['./user.ts'], + }, + }, + references: [ + { + // circular reference + path: './tsconfig.json', + }, + ], + }), + '/user.ts': 'export type User = { bar: string }', + } + + const { props, deps } = resolve( + ` + import { User } from 'user' + defineProps() + `, + files, + ) + + expect(props).toStrictEqual({ + bar: ['String'], + }) + expect(deps && [...deps]).toStrictEqual(['/user.ts']) + }) + test('ts module resolve w/ path aliased vue file', () => { const files = { '/tsconfig.json': JSON.stringify({ diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts index ee0a723991c..1e6433c56c8 100644 --- a/packages/compiler-sfc/src/script/resolveType.ts +++ b/packages/compiler-sfc/src/script/resolveType.ts @@ -1070,6 +1070,7 @@ function loadTSConfig( configPath: string, ts: typeof TS, fs: FS, + visited = new Set(), ): TS.ParsedCommandLine[] { // The only case where `fs` is NOT `ts.sys` is during tests. // parse config host requires an extra `readDirectory` method @@ -1089,14 +1090,18 @@ function loadTSConfig( configPath, ) const res = [config] + visited.add(configPath) if (config.projectReferences) { for (const ref of config.projectReferences) { const refPath = ts.resolveProjectReferencePath(ref) + if (visited.has(refPath)) { + continue + } if (!fs.fileExists(refPath)) { continue } tsConfigRefMap.set(refPath, configPath) - res.unshift(...loadTSConfig(refPath, ts, fs)) + res.unshift(...loadTSConfig(refPath, ts, fs, visited)) } } return res