test: refactor resolveType test
This commit is contained in:
parent
3982bef533
commit
34a007d00d
|
@ -1,4 +1,4 @@
|
||||||
import { TSTypeAliasDeclaration } from '@babel/types'
|
import { Identifier } from '@babel/types'
|
||||||
import { parse } from '../../src'
|
import { parse } from '../../src'
|
||||||
import { ScriptCompileContext } from '../../src/script/context'
|
import { ScriptCompileContext } from '../../src/script/context'
|
||||||
import {
|
import {
|
||||||
|
@ -14,13 +14,13 @@ registerTS(ts)
|
||||||
|
|
||||||
describe('resolveType', () => {
|
describe('resolveType', () => {
|
||||||
test('type literal', () => {
|
test('type literal', () => {
|
||||||
const { props, calls } = resolve(`type Target = {
|
const { props, calls } = resolve(`defineProps<{
|
||||||
foo: number // property
|
foo: number // property
|
||||||
bar(): void // method
|
bar(): void // method
|
||||||
'baz': string // string literal key
|
'baz': string // string literal key
|
||||||
(e: 'foo'): void // call signature
|
(e: 'foo'): void // call signature
|
||||||
(e: 'bar'): void
|
(e: 'bar'): void
|
||||||
}`)
|
}>()`)
|
||||||
expect(props).toStrictEqual({
|
expect(props).toStrictEqual({
|
||||||
foo: ['Number'],
|
foo: ['Number'],
|
||||||
bar: ['Function'],
|
bar: ['Function'],
|
||||||
|
@ -33,7 +33,7 @@ describe('resolveType', () => {
|
||||||
expect(
|
expect(
|
||||||
resolve(`
|
resolve(`
|
||||||
type Aliased = { foo: number }
|
type Aliased = { foo: number }
|
||||||
type Target = Aliased
|
defineProps<Aliased>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['Number']
|
foo: ['Number']
|
||||||
|
@ -44,7 +44,7 @@ describe('resolveType', () => {
|
||||||
expect(
|
expect(
|
||||||
resolve(`
|
resolve(`
|
||||||
export type Aliased = { foo: number }
|
export type Aliased = { foo: number }
|
||||||
type Target = Aliased
|
defineProps<Aliased>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['Number']
|
foo: ['Number']
|
||||||
|
@ -55,7 +55,7 @@ describe('resolveType', () => {
|
||||||
expect(
|
expect(
|
||||||
resolve(`
|
resolve(`
|
||||||
interface Aliased { foo: number }
|
interface Aliased { foo: number }
|
||||||
type Target = Aliased
|
defineProps<Aliased>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['Number']
|
foo: ['Number']
|
||||||
|
@ -66,7 +66,7 @@ describe('resolveType', () => {
|
||||||
expect(
|
expect(
|
||||||
resolve(`
|
resolve(`
|
||||||
export interface Aliased { foo: number }
|
export interface Aliased { foo: number }
|
||||||
type Target = Aliased
|
defineProps<Aliased>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['Number']
|
foo: ['Number']
|
||||||
|
@ -80,7 +80,7 @@ describe('resolveType', () => {
|
||||||
export interface B extends A { b: boolean }
|
export interface B extends A { b: boolean }
|
||||||
interface C { c: string }
|
interface C { c: string }
|
||||||
interface Aliased extends B, C { foo: number }
|
interface Aliased extends B, C { foo: number }
|
||||||
type Target = Aliased
|
defineProps<Aliased>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
a: ['Function'],
|
a: ['Function'],
|
||||||
|
@ -94,9 +94,7 @@ describe('resolveType', () => {
|
||||||
expect(
|
expect(
|
||||||
resolve(`
|
resolve(`
|
||||||
class Foo {}
|
class Foo {}
|
||||||
type Target = {
|
defineProps<{ foo: Foo }>()
|
||||||
foo: Foo
|
|
||||||
}
|
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['Object']
|
foo: ['Object']
|
||||||
|
@ -106,7 +104,7 @@ describe('resolveType', () => {
|
||||||
test('function type', () => {
|
test('function type', () => {
|
||||||
expect(
|
expect(
|
||||||
resolve(`
|
resolve(`
|
||||||
type Target = (e: 'foo') => void
|
defineProps<(e: 'foo') => void>()
|
||||||
`).calls?.length
|
`).calls?.length
|
||||||
).toBe(1)
|
).toBe(1)
|
||||||
})
|
})
|
||||||
|
@ -115,7 +113,7 @@ describe('resolveType', () => {
|
||||||
expect(
|
expect(
|
||||||
resolve(`
|
resolve(`
|
||||||
type Fn = (e: 'foo') => void
|
type Fn = (e: 'foo') => void
|
||||||
type Target = Fn
|
defineProps<Fn>()
|
||||||
`).calls?.length
|
`).calls?.length
|
||||||
).toBe(1)
|
).toBe(1)
|
||||||
})
|
})
|
||||||
|
@ -126,7 +124,7 @@ describe('resolveType', () => {
|
||||||
type Foo = { foo: number }
|
type Foo = { foo: number }
|
||||||
type Bar = { bar: string }
|
type Bar = { bar: string }
|
||||||
type Baz = { bar: string | boolean }
|
type Baz = { bar: string | boolean }
|
||||||
type Target = { self: any } & Foo & Bar & Baz
|
defineProps<{ self: any } & Foo & Bar & Baz>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
self: ['Unknown'],
|
self: ['Unknown'],
|
||||||
|
@ -156,7 +154,7 @@ describe('resolveType', () => {
|
||||||
note: string
|
note: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Target = CommonProps & ConditionalProps
|
defineProps<CommonProps & ConditionalProps>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
size: ['String'],
|
size: ['String'],
|
||||||
|
@ -171,9 +169,9 @@ describe('resolveType', () => {
|
||||||
resolve(`
|
resolve(`
|
||||||
type T = 'foo' | 'bar'
|
type T = 'foo' | 'bar'
|
||||||
type S = 'x' | 'y'
|
type S = 'x' | 'y'
|
||||||
type Target = {
|
defineProps<{
|
||||||
[\`_\${T}_\${S}_\`]: string
|
[\`_\${T}_\${S}_\`]: string
|
||||||
}
|
}>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
_foo_x_: ['String'],
|
_foo_x_: ['String'],
|
||||||
|
@ -187,7 +185,7 @@ describe('resolveType', () => {
|
||||||
expect(
|
expect(
|
||||||
resolve(`
|
resolve(`
|
||||||
type T = 'foo' | 'bar'
|
type T = 'foo' | 'bar'
|
||||||
type Target = { [K in T]: string | number } & {
|
defineProps<{ [K in T]: string | number } & {
|
||||||
[K in 'optional']?: boolean
|
[K in 'optional']?: boolean
|
||||||
} & {
|
} & {
|
||||||
[K in Capitalize<T>]: string
|
[K in Capitalize<T>]: string
|
||||||
|
@ -195,7 +193,7 @@ describe('resolveType', () => {
|
||||||
[K in Uppercase<Extract<T, 'foo'>>]: string
|
[K in Uppercase<Extract<T, 'foo'>>]: string
|
||||||
} & {
|
} & {
|
||||||
[K in \`x\${T}\`]: string
|
[K in \`x\${T}\`]: string
|
||||||
}
|
}>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['String', 'Number'],
|
foo: ['String', 'Number'],
|
||||||
|
@ -214,7 +212,7 @@ describe('resolveType', () => {
|
||||||
resolve(`
|
resolve(`
|
||||||
type T = { foo: number, bar: string, baz: boolean }
|
type T = { foo: number, bar: string, baz: boolean }
|
||||||
type K = 'foo' | 'bar'
|
type K = 'foo' | 'bar'
|
||||||
type Target = Pick<T, K>
|
defineProps<Pick<T, K>>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['Number'],
|
foo: ['Number'],
|
||||||
|
@ -227,7 +225,7 @@ describe('resolveType', () => {
|
||||||
resolve(`
|
resolve(`
|
||||||
type T = { foo: number, bar: string, baz: boolean }
|
type T = { foo: number, bar: string, baz: boolean }
|
||||||
type K = 'foo' | 'bar'
|
type K = 'foo' | 'bar'
|
||||||
type Target = Omit<T, K>
|
defineProps<Omit<T, K>>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
baz: ['Boolean']
|
baz: ['Boolean']
|
||||||
|
@ -239,7 +237,7 @@ describe('resolveType', () => {
|
||||||
resolve(`
|
resolve(`
|
||||||
type T = { bar: number }
|
type T = { bar: number }
|
||||||
type S = { nested: { foo: T['bar'] }}
|
type S = { nested: { foo: T['bar'] }}
|
||||||
type Target = S['nested']
|
defineProps<S['nested']>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['Number']
|
foo: ['Number']
|
||||||
|
@ -258,7 +256,7 @@ describe('resolveType', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
type Target = Foo.Bar.A
|
defineProps<Foo.Bar.A>()
|
||||||
`).props
|
`).props
|
||||||
).toStrictEqual({
|
).toStrictEqual({
|
||||||
foo: ['Number']
|
foo: ['Number']
|
||||||
|
@ -272,7 +270,7 @@ describe('resolveType', () => {
|
||||||
`
|
`
|
||||||
import { P } from './foo'
|
import { P } from './foo'
|
||||||
import { Y as PP } from './bar'
|
import { Y as PP } from './bar'
|
||||||
type Target = P & PP
|
defineProps<P & PP>()
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
'/foo.ts': 'export type P = { foo: number }',
|
'/foo.ts': 'export type P = { foo: number }',
|
||||||
|
@ -291,7 +289,7 @@ describe('resolveType', () => {
|
||||||
`
|
`
|
||||||
import { P } from './foo.vue'
|
import { P } from './foo.vue'
|
||||||
import { P as PP } from './bar.vue'
|
import { P as PP } from './bar.vue'
|
||||||
type Target = P & PP
|
defineProps<P & PP>()
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
'/foo.vue':
|
'/foo.vue':
|
||||||
|
@ -311,7 +309,7 @@ describe('resolveType', () => {
|
||||||
resolve(
|
resolve(
|
||||||
`
|
`
|
||||||
import { P } from './foo'
|
import { P } from './foo'
|
||||||
type Target = P
|
defineProps<P>()
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
'/foo.ts': `import type { P as PP } from './nested/bar.vue'
|
'/foo.ts': `import type { P as PP } from './nested/bar.vue'
|
||||||
|
@ -331,7 +329,7 @@ describe('resolveType', () => {
|
||||||
resolve(
|
resolve(
|
||||||
`
|
`
|
||||||
import { PP as P } from './foo'
|
import { PP as P } from './foo'
|
||||||
type Target = P
|
defineProps<P>()
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
'/foo.ts': `export { P as PP } from './bar'`,
|
'/foo.ts': `export { P as PP } from './bar'`,
|
||||||
|
@ -344,31 +342,31 @@ describe('resolveType', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('ts module resolve', () => {
|
test('ts module resolve', () => {
|
||||||
expect(
|
const files = {
|
||||||
resolve(
|
|
||||||
`
|
|
||||||
import { P } from 'foo'
|
|
||||||
import { PP } from 'bar'
|
|
||||||
type Target = P & PP
|
|
||||||
`,
|
|
||||||
{
|
|
||||||
'/node_modules/foo/package.json': JSON.stringify({
|
'/node_modules/foo/package.json': JSON.stringify({
|
||||||
name: 'foo',
|
|
||||||
version: '1.0.0',
|
|
||||||
types: 'index.d.ts'
|
types: 'index.d.ts'
|
||||||
}),
|
}),
|
||||||
'/node_modules/foo/index.d.ts': 'export type P = { foo: number }',
|
'/node_modules/foo/index.d.ts': 'export type P = { foo: number }',
|
||||||
'/tsconfig.json': JSON.stringify({
|
'/tsconfig.json': JSON.stringify({
|
||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
paths: {
|
paths: {
|
||||||
bar: ['./other/bar.ts']
|
bar: ['./pp.ts']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
'/other/bar.ts': 'export type PP = { bar: string }'
|
'/pp.ts': 'export type PP = { bar: string }'
|
||||||
}
|
}
|
||||||
).props
|
|
||||||
).toStrictEqual({
|
const { props } = resolve(
|
||||||
|
`
|
||||||
|
import { P } from 'foo'
|
||||||
|
import { PP } from 'bar'
|
||||||
|
defineProps<P & PP>()
|
||||||
|
`,
|
||||||
|
files
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(props).toStrictEqual({
|
||||||
foo: ['Number'],
|
foo: ['Number'],
|
||||||
bar: ['String']
|
bar: ['String']
|
||||||
})
|
})
|
||||||
|
@ -377,26 +375,26 @@ describe('resolveType', () => {
|
||||||
|
|
||||||
describe('errors', () => {
|
describe('errors', () => {
|
||||||
test('failed type reference', () => {
|
test('failed type reference', () => {
|
||||||
expect(() => resolve(`type Target = X`)).toThrow(
|
expect(() => resolve(`defineProps<X>()`)).toThrow(
|
||||||
`Unresolvable type reference`
|
`Unresolvable type reference`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('unsupported computed keys', () => {
|
test('unsupported computed keys', () => {
|
||||||
expect(() => resolve(`type Target = { [Foo]: string }`)).toThrow(
|
expect(() => resolve(`defineProps<{ [Foo]: string }>()`)).toThrow(
|
||||||
`Unsupported computed key in type referenced by a macro`
|
`Unsupported computed key in type referenced by a macro`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('unsupported index type', () => {
|
test('unsupported index type', () => {
|
||||||
expect(() => resolve(`type Target = X[K]`)).toThrow(
|
expect(() => resolve(`defineProps<X[K]>()`)).toThrow(
|
||||||
`Unsupported index type`
|
`Unsupported index type`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('failed improt source resolve', () => {
|
test('failed improt source resolve', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
resolve(`import { X } from './foo'; type Target = X`)
|
resolve(`import { X } from './foo'; defineProps<X>()`)
|
||||||
).toThrow(`Failed to resolve import source "./foo" for type X`)
|
).toThrow(`Failed to resolve import source "./foo" for type X`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -426,10 +424,17 @@ function resolve(code: string, files: Record<string, string> = {}) {
|
||||||
// skipping that here, so need to manually register imports
|
// skipping that here, so need to manually register imports
|
||||||
ctx.userImports = recordImports(ctx.scriptSetupAst!.body) as any
|
ctx.userImports = recordImports(ctx.scriptSetupAst!.body) as any
|
||||||
|
|
||||||
const targetDecl = ctx.scriptSetupAst!.body.find(
|
let target: any
|
||||||
s => s.type === 'TSTypeAliasDeclaration' && s.id.name === 'Target'
|
for (const s of ctx.scriptSetupAst!.body) {
|
||||||
) as TSTypeAliasDeclaration
|
if (
|
||||||
const raw = resolveTypeElements(ctx, targetDecl.typeAnnotation)
|
s.type === 'ExpressionStatement' &&
|
||||||
|
s.expression.type === 'CallExpression' &&
|
||||||
|
(s.expression.callee as Identifier).name === 'defineProps'
|
||||||
|
) {
|
||||||
|
target = s.expression.typeParameters!.params[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const raw = resolveTypeElements(ctx, target)
|
||||||
const props: Record<string, string[]> = {}
|
const props: Record<string, string[]> = {}
|
||||||
for (const key in raw.props) {
|
for (const key in raw.props) {
|
||||||
props[key] = inferRuntimeType(ctx, raw.props[key])
|
props[key] = inferRuntimeType(ctx, raw.props[key])
|
||||||
|
|
Loading…
Reference in New Issue