Skip to content

Commit f7ce5ae

Browse files
authored
fix(compiler-sfc): simulate allowArbitraryExtensions on resolving type (#13301)
close #13295
1 parent 772b008 commit f7ce5ae

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,29 @@ describe('resolveType', () => {
14341434
colsLg: ['Number'],
14351435
})
14361436
})
1437+
1438+
test('allowArbitraryExtensions', () => {
1439+
const files = {
1440+
'/foo.d.vue.ts': 'export type Foo = number;',
1441+
'/foo.vue': '<template><div /></template>',
1442+
'/bar.d.css.ts': 'export type Bar = string;',
1443+
'/bar.css': ':root { --color: red; }',
1444+
}
1445+
1446+
const { props } = resolve(
1447+
`
1448+
import { Foo } from './foo.vue'
1449+
import { Bar } from './bar.css'
1450+
defineProps<{ foo: Foo; bar: Bar }>()
1451+
`,
1452+
files,
1453+
)
1454+
1455+
expect(props).toStrictEqual({
1456+
foo: ['Number'],
1457+
bar: ['String'],
1458+
})
1459+
})
14371460
})
14381461
})
14391462

packages/compiler-sfc/src/script/resolveType.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -860,13 +860,13 @@ function resolveFS(ctx: TypeResolveContext): FS | undefined {
860860
}
861861
return (ctx.fs = {
862862
fileExists(file) {
863-
if (file.endsWith('.vue.ts')) {
863+
if (file.endsWith('.vue.ts') && !file.endsWith('.d.vue.ts')) {
864864
file = file.replace(/\.ts$/, '')
865865
}
866866
return fs.fileExists(file)
867867
},
868868
readFile(file) {
869-
if (file.endsWith('.vue.ts')) {
869+
if (file.endsWith('.vue.ts') && !file.endsWith('.d.vue.ts')) {
870870
file = file.replace(/\.ts$/, '')
871871
}
872872
return fs.readFile(file)
@@ -1059,7 +1059,7 @@ function resolveWithTS(
10591059

10601060
if (res.resolvedModule) {
10611061
let filename = res.resolvedModule.resolvedFileName
1062-
if (filename.endsWith('.vue.ts')) {
1062+
if (filename.endsWith('.vue.ts') && !filename.endsWith('.d.vue.ts')) {
10631063
filename = filename.replace(/\.ts$/, '')
10641064
}
10651065
return fs.realpath ? fs.realpath(filename) : filename
@@ -1129,7 +1129,7 @@ export function fileToScope(
11291129
// fs should be guaranteed to exist here
11301130
const fs = resolveFS(ctx)!
11311131
const source = fs.readFile(filename) || ''
1132-
const body = parseFile(filename, source, ctx.options.babelParserPlugins)
1132+
const body = parseFile(filename, source, fs, ctx.options.babelParserPlugins)
11331133
const scope = new TypeScope(filename, source, 0, recordImports(body))
11341134
recordTypes(ctx, body, scope, asGlobal)
11351135
fileToScopeCache.set(filename, scope)
@@ -1139,6 +1139,7 @@ export function fileToScope(
11391139
function parseFile(
11401140
filename: string,
11411141
content: string,
1142+
fs: FS,
11421143
parserPlugins?: SFCScriptCompileOptions['babelParserPlugins'],
11431144
): Statement[] {
11441145
const ext = extname(filename)
@@ -1151,7 +1152,21 @@ function parseFile(
11511152
),
11521153
sourceType: 'module',
11531154
}).program.body
1154-
} else if (ext === '.vue') {
1155+
}
1156+
1157+
// simulate `allowArbitraryExtensions` on TypeScript >= 5.0
1158+
const isUnknownTypeSource = !/\.[cm]?[tj]sx?$/.test(filename)
1159+
const arbitraryTypeSource = `${filename.slice(0, -ext.length)}.d${ext}.ts`
1160+
const hasArbitraryTypeDeclaration =
1161+
isUnknownTypeSource && fs.fileExists(arbitraryTypeSource)
1162+
if (hasArbitraryTypeDeclaration) {
1163+
return babelParse(fs.readFile(arbitraryTypeSource)!, {
1164+
plugins: resolveParserPlugins('ts', parserPlugins, true),
1165+
sourceType: 'module',
1166+
}).program.body
1167+
}
1168+
1169+
if (ext === '.vue') {
11551170
const {
11561171
descriptor: { script, scriptSetup },
11571172
} = parse(content)

0 commit comments

Comments
 (0)