wip: test for runtime props/emits extraction

This commit is contained in:
Evan You 2020-07-09 12:16:08 -04:00
parent 2c3cdab93d
commit 18c537d3c2
3 changed files with 169 additions and 10 deletions

View File

@ -1,5 +1,92 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SFC compile <script setup> <script setup lang="ts"> extract emits 1`] = `
"import { defineComponent as __define__ } from 'vue'
import { Slots as __Slots__ } from 'vue'
declare function __emit__(e: 'foo' | 'bar'): void
declare function __emit__(e: 'baz', id: number): void
export function setup(_: {}, { emit: myEmit }: {
emit: typeof __emit__,
slots: __Slots__,
attrs: Record<string, any>
}) {
return { }
}
export default __define__({
emits: [\\"foo\\", \\"bar\\", \\"baz\\"] as unknown as undefined,
setup
})"
`;
exports[`SFC compile <script setup> <script setup lang="ts"> extract props 1`] = `
"import { defineComponent as __define__ } from 'vue'
import { Slots as __Slots__ } from 'vue'
interface Test {}
type Alias = number[]
export function setup(myProps: {
string: string
number: number
boolean: boolean
object: object
objectLiteral: { a: number }
fn: (n: number) => void
functionRef: Function
objectRef: Object
array: string[]
arrayRef: Array<any>
tuple: [number, number]
set: Set<string>
literal: 'foo'
optional?: any
recordRef: Record<string, null>
interface: Test
alias: Alias
union: string | number
literalUnion: 'foo' | 'bar'
literalUnionMixed: 'foo' | 1 | boolean
intersection: Test & {}
}) {
return { }
}
export default __define__({
props: {
string: { type: String, required: true },
number: { type: Number, required: true },
boolean: { type: Boolean, required: true },
object: { type: Object, required: true },
objectLiteral: { type: Object, required: true },
fn: { type: Function, required: true },
functionRef: { type: Function, required: true },
objectRef: { type: Object, required: true },
array: { type: Array, required: true },
arrayRef: { type: Array, required: true },
tuple: { type: Array, required: true },
set: { type: Set, required: true },
literal: { type: String, required: true },
optional: { type: null, required: false },
recordRef: { type: Object, required: true },
interface: { type: Object, required: true },
alias: { type: Array, required: true },
union: { type: [String, Number], required: true },
literalUnion: { type: [String, String], required: true },
literalUnionMixed: { type: [String, Number, Boolean], required: true },
intersection: { type: Object, required: true }
} as unknown as undefined,
setup
})"
`;
exports[`SFC compile <script setup> <script setup lang="ts"> hoist type declarations 1`] = ` exports[`SFC compile <script setup> <script setup lang="ts"> hoist type declarations 1`] = `
"import { defineComponent as __define__ } from 'vue' "import { defineComponent as __define__ } from 'vue'
import { Slots as __Slots__ } from 'vue' import { Slots as __Slots__ } from 'vue'

View File

@ -205,9 +205,82 @@ describe('SFC compile <script setup>', () => {
expect(bindings).toStrictEqual({ a: 'setup' }) expect(bindings).toStrictEqual({ a: 'setup' })
}) })
test('extract props', () => {}) test('extract props', () => {
const { code } = compile(`
<script setup="myProps" lang="ts">
interface Test {}
test('extract emits', () => {}) type Alias = number[]
declare const myProps: {
string: string
number: number
boolean: boolean
object: object
objectLiteral: { a: number }
fn: (n: number) => void
functionRef: Function
objectRef: Object
array: string[]
arrayRef: Array<any>
tuple: [number, number]
set: Set<string>
literal: 'foo'
optional?: any
recordRef: Record<string, null>
interface: Test
alias: Alias
union: string | number
literalUnion: 'foo' | 'bar'
literalUnionMixed: 'foo' | 1 | boolean
intersection: Test & {}
}
</script>`)
assertCode(code)
expect(code).toMatch(`string: { type: String, required: true }`)
expect(code).toMatch(`number: { type: Number, required: true }`)
expect(code).toMatch(`boolean: { type: Boolean, required: true }`)
expect(code).toMatch(`object: { type: Object, required: true }`)
expect(code).toMatch(`objectLiteral: { type: Object, required: true }`)
expect(code).toMatch(`fn: { type: Function, required: true }`)
expect(code).toMatch(`functionRef: { type: Function, required: true }`)
expect(code).toMatch(`objectRef: { type: Object, required: true }`)
expect(code).toMatch(`array: { type: Array, required: true }`)
expect(code).toMatch(`arrayRef: { type: Array, required: true }`)
expect(code).toMatch(`tuple: { type: Array, required: true }`)
expect(code).toMatch(`set: { type: Set, required: true }`)
expect(code).toMatch(`literal: { type: String, required: true }`)
expect(code).toMatch(`optional: { type: null, required: false }`)
expect(code).toMatch(`recordRef: { type: Object, required: true }`)
expect(code).toMatch(`interface: { type: Object, required: true }`)
expect(code).toMatch(`alias: { type: Array, required: true }`)
expect(code).toMatch(`union: { type: [String, Number], required: true }`)
expect(code).toMatch(
`literalUnion: { type: [String, String], required: true }`
)
expect(code).toMatch(
`literalUnionMixed: { type: [String, Number, Boolean], required: true }`
)
expect(code).toMatch(`intersection: { type: Object, required: true }`)
})
test('extract emits', () => {
const { code } = compile(`
<script setup="_, { emit: myEmit }" lang="ts">
declare function myEmit(e: 'foo' | 'bar'): void
declare function myEmit(e: 'baz', id: number): void
</script>
`)
assertCode(code)
expect(code).toMatch(`declare function __emit__(e: 'foo' | 'bar'): void`)
expect(code).toMatch(
`declare function __emit__(e: 'baz', id: number): void`
)
expect(code).toMatch(
`emits: ["foo", "bar", "baz"] as unknown as undefined`
)
})
}) })
describe('errors', () => { describe('errors', () => {

View File

@ -420,7 +420,7 @@ export function compileScriptSetup(
} }
} }
// check default export to make sure it doesn't reference setup scope // 4. check default export to make sure it doesn't reference setup scope
// variables // variables
if (needDefaultExportRefCheck) { if (needDefaultExportRefCheck) {
checkDefaultExport( checkDefaultExport(
@ -433,7 +433,7 @@ export function compileScriptSetup(
) )
} }
// remove non-script content // 5. remove non-script content
if (script) { if (script) {
if (startOffset < scriptStartOffset!) { if (startOffset < scriptStartOffset!) {
// <script setup> before <script> // <script setup> before <script>
@ -451,8 +451,7 @@ export function compileScriptSetup(
s.remove(endOffset, source.length) s.remove(endOffset, source.length)
} }
// wrap setup code with function // 5. finalize setup argument signature.
// finalize the argument signature.
let args = `` let args = ``
if (isTS) { if (isTS) {
if (slotsType === '__Slots__') { if (slotsType === '__Slots__') {
@ -480,6 +479,7 @@ export function compileScriptSetup(
args = hasExplicitSignature ? (scriptSetup.setup as string) : `` args = hasExplicitSignature ? (scriptSetup.setup as string) : ``
} }
// 6. wrap setup code with function.
// export the content of <script setup> as a named export, `setup`. // export the content of <script setup> as a named export, `setup`.
// this allows `import { setup } from '*.vue'` for testing purposes. // this allows `import { setup } from '*.vue'` for testing purposes.
s.appendLeft(startOffset, `\nexport function setup(${args}) {\n`) s.appendLeft(startOffset, `\nexport function setup(${args}) {\n`)
@ -499,7 +499,7 @@ export function compileScriptSetup(
s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`) s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
// finalize default export // 7. finalize default export
if (isTS) { if (isTS) {
// for TS, make sure the exported type is still valid type with // for TS, make sure the exported type is still valid type with
// correct props information // correct props information
@ -520,9 +520,7 @@ export function compileScriptSetup(
} }
} }
s.trim() // 8. expose bindings for template compiler optimization
// analyze bindings for template compiler optimization
if (script) { if (script) {
Object.assign(bindings, analyzeScriptBindings(script)) Object.assign(bindings, analyzeScriptBindings(script))
} }
@ -530,6 +528,7 @@ export function compileScriptSetup(
bindings[key] = 'setup' bindings[key] = 'setup'
}) })
s.trim()
return { return {
bindings, bindings,
code: s.toString(), code: s.toString(),