Skip to content

Commit f0c2841

Browse files
committed
refactor: improve + handle object method
1 parent 78023ec commit f0c2841

File tree

3 files changed

+78
-50
lines changed

3 files changed

+78
-50
lines changed

packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap

+3-6
Original file line numberDiff line numberDiff line change
@@ -1063,13 +1063,10 @@ export default /*#__PURE__*/_defineComponent({
10631063
props: {
10641064
foo: { type: String, required: false, default: 'hi' },
10651065
bar: { type: Number, required: false },
1066-
baz: { type: Boolean, required: true }
1066+
baz: { type: Boolean, required: true },
1067+
qux: { type: Function, required: false, default() { return 1 } }
10671068
} as unknown as undefined,
1068-
setup(__props: {
1069-
foo: string
1070-
bar?: number
1071-
baz: boolean
1072-
}, { expose }) {
1069+
setup(__props: { foo: string, bar?: number, baz: boolean, qux(): number }, { expose }) {
10731070
expose()
10741071
10751072
const props = __props

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

+10-6
Original file line numberDiff line numberDiff line change
@@ -801,8 +801,10 @@ const emit = defineEmits(['a', 'b'])
801801
foo?: string
802802
bar?: number
803803
baz: boolean
804+
qux?(): number
804805
}>(), {
805-
foo: 'hi'
806+
foo: 'hi',
807+
qux() { return 1 }
806808
})
807809
</script>
808810
`)
@@ -812,16 +814,18 @@ const emit = defineEmits(['a', 'b'])
812814
)
813815
expect(content).toMatch(`bar: { type: Number, required: false }`)
814816
expect(content).toMatch(`baz: { type: Boolean, required: true }`)
815-
expect(content).toMatch(`{
816-
foo: string
817-
bar?: number
818-
baz: boolean
819-
}`)
817+
expect(content).toMatch(
818+
`qux: { type: Function, required: false, default() { return 1 } }`
819+
)
820+
expect(content).toMatch(
821+
`{ foo: string, bar?: number, baz: boolean, qux(): number }`
822+
)
820823
expect(content).toMatch(`const props = __props`)
821824
expect(bindings).toStrictEqual({
822825
foo: BindingTypes.PROPS,
823826
bar: BindingTypes.PROPS,
824827
baz: BindingTypes.PROPS,
828+
qux: BindingTypes.PROPS,
825829
props: BindingTypes.SETUP_CONST
826830
})
827831
})

packages/compiler-sfc/src/compileScript.ts

+65-38
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ import {
3838
RestElement,
3939
TSInterfaceBody,
4040
AwaitExpression,
41-
Program
41+
Program,
42+
ObjectMethod
4243
} from '@babel/types'
4344
import { walk } from 'estree-walker'
4445
import { RawSourceMap } from 'source-map'
@@ -242,7 +243,7 @@ export function compileScript(
242243
let hasDefineEmitCall = false
243244
let hasDefineExposeCall = false
244245
let propsRuntimeDecl: Node | undefined
245-
let propsRuntimeDefaults: Node | undefined
246+
let propsRuntimeDefaults: ObjectExpression | undefined
246247
let propsTypeDecl: TSTypeLiteral | TSInterfaceBody | undefined
247248
let propsTypeDeclRaw: Node | undefined
248249
let propsIdentifier: string | undefined
@@ -384,7 +385,16 @@ export function compileScript(
384385
node
385386
)
386387
}
387-
propsRuntimeDefaults = node.arguments[1]
388+
propsRuntimeDefaults = node.arguments[1] as ObjectExpression
389+
if (
390+
!propsRuntimeDefaults ||
391+
propsRuntimeDefaults.type !== 'ObjectExpression'
392+
) {
393+
error(
394+
`The 2nd argument of ${WITH_DEFAULTS} must be an object literal.`,
395+
propsRuntimeDefaults || node
396+
)
397+
}
388398
} else {
389399
error(
390400
`${WITH_DEFAULTS}' first argument must be a ${DEFINE_PROPS} call.`,
@@ -523,7 +533,9 @@ export function compileScript(
523533
propsRuntimeDefaults &&
524534
propsRuntimeDefaults.type === 'ObjectExpression' &&
525535
propsRuntimeDefaults.properties.every(
526-
node => node.type === 'ObjectProperty' && !node.computed
536+
node =>
537+
(node.type === 'ObjectProperty' && !node.computed) ||
538+
node.type === 'ObjectMethod'
527539
)
528540
)
529541
}
@@ -534,22 +546,28 @@ export function compileScript(
534546
return ``
535547
}
536548
const hasStaticDefaults = checkStaticDefaults()
549+
const scriptSetupSource = scriptSetup!.content
537550
let propsDecls = `{
538551
${keys
539552
.map(key => {
540553
let defaultString: string | undefined
541554
if (hasStaticDefaults) {
542-
const prop = (
543-
propsRuntimeDefaults as ObjectExpression
544-
).properties.find(
555+
const prop = propsRuntimeDefaults!.properties.find(
545556
(node: any) => node.key.name === key
546-
) as ObjectProperty
557+
) as ObjectProperty | ObjectMethod
547558
if (prop) {
548-
// prop has corresponding static default value
549-
defaultString = `default: ${source.slice(
550-
prop.value.start! + startOffset,
551-
prop.value.end! + startOffset
552-
)}`
559+
if (prop.type === 'ObjectProperty') {
560+
// prop has corresponding static default value
561+
defaultString = `default: ${scriptSetupSource.slice(
562+
prop.value.start!,
563+
prop.value.end!
564+
)}`
565+
} else {
566+
defaultString = `default() ${scriptSetupSource.slice(
567+
prop.body.start!,
568+
prop.body.end!
569+
)}`
570+
}
553571
}
554572
}
555573
@@ -577,29 +595,42 @@ export function compileScript(
577595
return `\n props: ${propsDecls} as unknown as undefined,`
578596
}
579597

580-
function genSetupPropsType(
581-
props: Record<string, PropTypeData>,
582-
propsType: string
583-
) {
584-
const keys = Object.keys(props)
585-
if (!keys.length) {
586-
return ``
587-
}
588-
const hasStaticDefaults = checkStaticDefaults()
589-
keys.map(key => {
590-
if (hasStaticDefaults) {
591-
const prop = (propsRuntimeDefaults as ObjectExpression).properties.find(
592-
(node: any) => node.key.name === key
593-
) as ObjectProperty
594-
if (prop) {
595-
const { required } = props[key]
596-
if (!required) {
597-
propsType = propsType.replace(`${key}?`, key)
598+
function genSetupPropsType(node: TSTypeLiteral | TSInterfaceBody) {
599+
const scriptSetupSource = scriptSetup!.content
600+
if (checkStaticDefaults()) {
601+
// if withDefaults() is used, we need to remove the optional flags
602+
// on props that have default values
603+
let res = `: { `
604+
const members = node.type === 'TSTypeLiteral' ? node.members : node.body
605+
for (const m of members) {
606+
if (
607+
(m.type === 'TSPropertySignature' ||
608+
m.type === 'TSMethodSignature') &&
609+
m.typeAnnotation &&
610+
m.key.type === 'Identifier'
611+
) {
612+
if (
613+
propsRuntimeDefaults!.properties.some(
614+
(p: any) => p.key.name === (m.key as Identifier).name
615+
)
616+
) {
617+
res +=
618+
m.key.name +
619+
(m.type === 'TSMethodSignature' ? '()' : '') +
620+
scriptSetupSource.slice(
621+
m.typeAnnotation.start!,
622+
m.typeAnnotation.end!
623+
) +
624+
', '
625+
} else {
626+
res += scriptSetupSource.slice(m.start!, m.end!) + `, `
598627
}
599628
}
600629
}
601-
})
602-
return `: ${propsType}`
630+
return (res.length ? res.slice(0, -2) : res) + ` }`
631+
} else {
632+
return `: ${scriptSetupSource.slice(node.start!, node.end!)}`
633+
}
603634
}
604635

605636
// 1. process normal <script> first if it exists
@@ -1020,11 +1051,7 @@ export function compileScript(
10201051
// 9. finalize setup() argument signature
10211052
let args = `__props`
10221053
if (propsTypeDecl) {
1023-
const propsType = `${scriptSetup.content.slice(
1024-
propsTypeDecl.start!,
1025-
propsTypeDecl.end!
1026-
)}`
1027-
args += genSetupPropsType(typeDeclaredProps, propsType)
1054+
args += genSetupPropsType(propsTypeDecl)
10281055
}
10291056
// inject user assignment of props
10301057
// we use a default __props so that template expressions referencing props

0 commit comments

Comments
 (0)