diff --git a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts index 68fc5cc3159..6b4770ecb7d 100644 --- a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts @@ -1155,6 +1155,45 @@ describe('resolveType', () => { expect(deps && [...deps]).toStrictEqual(['/user.ts']) }) + // #13484 + test('ts module resolve w/ project reference & extends & ${configDir}', () => { + const files = { + '/tsconfig.json': JSON.stringify({ + files: [], + references: [{ path: './tsconfig.app.json' }], + }), + '/tsconfig.app.json': JSON.stringify({ + extends: ['./tsconfigs/base.json'], + }), + '/tsconfigs/base.json': JSON.stringify({ + compilerOptions: { + paths: { + '@/*': ['${configDir}/src/*'], + }, + }, + include: ['${configDir}/src/**/*.ts', '${configDir}/src/**/*.vue'], + }), + '/src/types.ts': + 'export type BaseProps = { foo?: string, bar?: string }', + } + + const { props, deps } = resolve( + ` + import { BaseProps } from '@/types.ts'; + defineProps() + `, + files, + {}, + '/src/components/Foo.vue', + ) + + expect(props).toStrictEqual({ + foo: ['String'], + bar: ['String'], + }) + expect(deps && [...deps]).toStrictEqual(['/src/types.ts']) + }) + test('ts module resolve w/ project reference folder', () => { 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 85832dfc39a..ae7bcbfe170 100644 --- a/packages/compiler-sfc/src/script/resolveType.ts +++ b/packages/compiler-sfc/src/script/resolveType.ts @@ -1029,6 +1029,14 @@ function resolveWithTS( if (configs.length === 1) { matchedConfig = configs[0] } else { + const [major, minor] = ts.versionMajorMinor.split('.').map(Number) + const getPattern = (base: string, p: string) => { + // ts 5.5+ supports ${configDir} in paths + const supportsConfigDir = major > 5 || (major === 5 && minor >= 5) + return p.startsWith('${configDir}') && supportsConfigDir + ? normalizePath(p.replace('${configDir}', dirname(configPath!))) + : joinPaths(base, p) + } // resolve which config matches the current file for (const c of configs) { const base = normalizePath( @@ -1039,11 +1047,11 @@ function resolveWithTS( const excluded: string[] | undefined = c.config.raw?.exclude if ( (!included && (!base || containingFile.startsWith(base))) || - included?.some(p => isMatch(containingFile, joinPaths(base, p))) + included?.some(p => isMatch(containingFile, getPattern(base, p))) ) { if ( excluded && - excluded.some(p => isMatch(containingFile, joinPaths(base, p))) + excluded.some(p => isMatch(containingFile, getPattern(base, p))) ) { continue }