Skip to content

Commit

Permalink
fix(compiler-sfc): fix type import from path aliased vue file
Browse files Browse the repository at this point in the history
close #8348
  • Loading branch information
yyx990803 committed May 18, 2023
1 parent 8ec73a3 commit fab9c72
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 6 deletions.
28 changes: 28 additions & 0 deletions packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
Expand Up @@ -685,6 +685,34 @@ describe('resolveType', () => {
expect(deps && [...deps]).toStrictEqual(['/user.ts'])
})

test('ts module resolve w/ path aliased vue file', () => {
const files = {
'/tsconfig.json': JSON.stringify({
compilerOptions: {
include: ['**/*.ts', '**/*.vue'],
paths: {
'@/*': ['./src/*']
}
}
}),
'/src/Foo.vue':
'<script lang="ts">export type P = { bar: string }</script>'
}

const { props, deps } = resolve(
`
import { P } from '@/Foo.vue'
defineProps<P>()
`,
files
)

expect(props).toStrictEqual({
bar: ['String']
})
expect(deps && [...deps]).toStrictEqual(['/src/Foo.vue'])
})

test('global types', () => {
const files = {
// ambient
Expand Down
5 changes: 5 additions & 0 deletions packages/compiler-sfc/src/script/context.ts
Expand Up @@ -70,6 +70,11 @@ export class ScriptCompileContext {
*/
deps?: Set<string>

/**
* cache for resolved fs
*/
fs?: NonNullable<SFCScriptCompileOptions['fs']>

constructor(
public descriptor: SFCDescriptor,
public options: Partial<SFCScriptCompileOptions>
Expand Down
42 changes: 36 additions & 6 deletions packages/compiler-sfc/src/script/resolveType.ts
Expand Up @@ -62,7 +62,9 @@ export type SimpleTypeResolveContext = Pick<
// required
'source' | 'filename' | 'error' | 'options'
> &
Partial<Pick<ScriptCompileContext, 'scope' | 'globalScopes' | 'deps'>> & {
Partial<
Pick<ScriptCompileContext, 'scope' | 'globalScopes' | 'deps' | 'fs'>
> & {
ast: Statement[]
}

Expand Down Expand Up @@ -693,7 +695,7 @@ function qualifiedNameToPath(node: Identifier | TSQualifiedName): string[] {

function resolveGlobalScope(ctx: TypeResolveContext): TypeScope[] | undefined {
if (ctx.options.globalTypeFiles) {
const fs: FS = ctx.options.fs || ts?.sys
const fs = resolveFS(ctx)
if (!fs) {
throw new Error('[vue/compiler-sfc] globalTypeFiles requires fs access.')
}
Expand All @@ -714,6 +716,30 @@ export function registerTS(_ts: any) {

type FS = NonNullable<SFCScriptCompileOptions['fs']>

function resolveFS(ctx: TypeResolveContext): FS | undefined {
if (ctx.fs) {
return ctx.fs
}
const fs = ctx.options.fs || ts.sys
if (!fs) {
return
}
return (ctx.fs = {
fileExists(file) {
if (file.endsWith('.vue.ts')) {
file = file.replace(/\.ts$/, '')
}
return fs.fileExists(file)
},
readFile(file) {
if (file.endsWith('.vue.ts')) {
file = file.replace(/\.ts$/, '')
}
return fs.readFile(file)
}
})
}

function resolveTypeFromImport(
ctx: TypeResolveContext,
node: ReferenceTypes,
Expand All @@ -731,9 +757,9 @@ function importSourceToScope(
scope: TypeScope,
source: string
): TypeScope {
const fs: FS = ctx.options.fs || ts?.sys
const fs = resolveFS(ctx)
if (!fs) {
ctx.error(
return ctx.error(
`No fs option provided to \`compileScript\` in non-Node environment. ` +
`File system access is required for resolving imported types.`,
node,
Expand Down Expand Up @@ -881,7 +907,11 @@ function resolveWithTS(
)

if (res.resolvedModule) {
return res.resolvedModule.resolvedFileName
let filename = res.resolvedModule.resolvedFileName
if (filename.endsWith('.vue.ts')) {
filename = filename.replace(/\.ts$/, '')
}
return filename
}
}

Expand Down Expand Up @@ -936,7 +966,7 @@ export function fileToScope(
return cached
}
// fs should be guaranteed to exist here
const fs = ctx.options.fs || ts?.sys
const fs = resolveFS(ctx)!
const source = fs.readFile(filename) || ''
const body = parseFile(filename, source, ctx.options.babelParserPlugins)
const scope = new TypeScope(filename, source, 0, recordImports(body))
Expand Down

0 comments on commit fab9c72

Please sign in to comment.