@@ -62,6 +62,7 @@ const DEFINE_PROPS = 'defineProps'
62
62
const DEFINE_EMITS = 'defineEmits'
63
63
const DEFINE_EXPOSE = 'defineExpose'
64
64
const WITH_DEFAULTS = 'withDefaults'
65
+ const DEFINE_OPTIONS = 'defineOptions'
65
66
66
67
// constants
67
68
const DEFAULT_VAR = `__default__`
@@ -270,6 +271,7 @@ export function compileScript(
270
271
let hasDefineExposeCall = false
271
272
let hasDefaultExportName = false
272
273
let hasDefaultExportRender = false
274
+ let hasDefineOptionsCall = false
273
275
let propsRuntimeDecl : Node | undefined
274
276
let propsRuntimeDefaults : ObjectExpression | undefined
275
277
let propsDestructureDecl : Node | undefined
@@ -281,6 +283,7 @@ export function compileScript(
281
283
let emitsTypeDecl : EmitsDeclType | undefined
282
284
let emitsTypeDeclRaw : Node | undefined
283
285
let emitIdentifier : string | undefined
286
+ let optionsRuntimeDecl : Node | undefined
284
287
let hasAwait = false
285
288
let hasInlinedSsrRenderFn = false
286
289
// props/emits declared via types
@@ -647,6 +650,50 @@ export function compileScript(
647
650
} )
648
651
}
649
652
653
+ function processDefineOptions ( node : Node ) : boolean {
654
+ if ( ! isCallOf ( node , DEFINE_OPTIONS ) ) {
655
+ return false
656
+ }
657
+ if ( hasDefineOptionsCall ) {
658
+ error ( `duplicate ${ DEFINE_OPTIONS } () call` , node )
659
+ }
660
+ if ( node . typeParameters ) {
661
+ error ( `${ DEFINE_OPTIONS } () cannot accept type arguments` , node )
662
+ }
663
+
664
+ hasDefineOptionsCall = true
665
+ optionsRuntimeDecl = node . arguments [ 0 ]
666
+
667
+ let propsOption = undefined
668
+ let emitsOption = undefined
669
+ if ( optionsRuntimeDecl . type === 'ObjectExpression' ) {
670
+ for ( const prop of optionsRuntimeDecl . properties ) {
671
+ if (
672
+ ( prop . type === 'ObjectProperty' || prop . type === 'ObjectMethod' ) &&
673
+ prop . key . type === 'Identifier'
674
+ ) {
675
+ if ( prop . key . name === 'props' ) propsOption = prop
676
+ if ( prop . key . name === 'emits' ) emitsOption = prop
677
+ }
678
+ }
679
+ }
680
+
681
+ if ( propsOption ) {
682
+ error (
683
+ `${ DEFINE_OPTIONS } () cannot be used to declare props. Use ${ DEFINE_PROPS } () instead.` ,
684
+ propsOption
685
+ )
686
+ }
687
+ if ( emitsOption ) {
688
+ error (
689
+ `${ DEFINE_OPTIONS } () cannot be used to declare emits. Use ${ DEFINE_EMITS } () instead.` ,
690
+ emitsOption
691
+ )
692
+ }
693
+
694
+ return true
695
+ }
696
+
650
697
function resolveQualifiedType (
651
698
node : Node ,
652
699
qualifier : ( node : Node ) => boolean
@@ -1175,6 +1222,7 @@ export function compileScript(
1175
1222
if (
1176
1223
processDefineProps ( node . expression ) ||
1177
1224
processDefineEmits ( node . expression ) ||
1225
+ processDefineOptions ( node . expression ) ||
1178
1226
processWithDefaults ( node . expression )
1179
1227
) {
1180
1228
s . remove ( node . start ! + startOffset , node . end ! + startOffset )
@@ -1195,6 +1243,13 @@ export function compileScript(
1195
1243
for ( let i = 0 ; i < total ; i ++ ) {
1196
1244
const decl = node . declarations [ i ]
1197
1245
if ( decl . init ) {
1246
+ if ( processDefineOptions ( decl . init ) ) {
1247
+ error (
1248
+ `${ DEFINE_OPTIONS } () has no returning value, it cannot be assigned.` ,
1249
+ node
1250
+ )
1251
+ }
1252
+
1198
1253
// defineProps / defineEmits
1199
1254
const isDefineProps =
1200
1255
processDefineProps ( decl . init , decl . id , node . kind ) ||
@@ -1339,6 +1394,7 @@ export function compileScript(
1339
1394
checkInvalidScopeReference ( propsRuntimeDefaults , DEFINE_PROPS )
1340
1395
checkInvalidScopeReference ( propsDestructureDecl , DEFINE_PROPS )
1341
1396
checkInvalidScopeReference ( emitsRuntimeDecl , DEFINE_EMITS )
1397
+ checkInvalidScopeReference ( optionsRuntimeDecl , DEFINE_OPTIONS )
1342
1398
1343
1399
// 6. remove non-script content
1344
1400
if ( script ) {
@@ -1626,6 +1682,13 @@ export function compileScript(
1626
1682
runtimeOptions += genRuntimeEmits ( typeDeclaredEmits )
1627
1683
}
1628
1684
1685
+ let definedOptions = ''
1686
+ if ( optionsRuntimeDecl ) {
1687
+ definedOptions = scriptSetup . content
1688
+ . slice ( optionsRuntimeDecl . start ! , optionsRuntimeDecl . end ! )
1689
+ . trim ( )
1690
+ }
1691
+
1629
1692
// <script setup> components are closed by default. If the user did not
1630
1693
// explicitly call `defineExpose`, call expose() with no args.
1631
1694
const exposeCall =
@@ -1637,7 +1700,9 @@ export function compileScript(
1637
1700
// we have to use object spread for types to be merged properly
1638
1701
// user's TS setting should compile it down to proper targets
1639
1702
// export default defineComponent({ ...__default__, ... })
1640
- const def = defaultExport ? `\n ...${ DEFAULT_VAR } ,` : ``
1703
+ const def =
1704
+ ( defaultExport ? `\n ...${ DEFAULT_VAR } ,` : `` ) +
1705
+ ( definedOptions ? `\n ...${ definedOptions } ,` : '' )
1641
1706
s . prependLeft (
1642
1707
startOffset ,
1643
1708
`\nexport default /*#__PURE__*/${ helper (
@@ -1648,12 +1713,14 @@ export function compileScript(
1648
1713
)
1649
1714
s . appendRight ( endOffset , `})` )
1650
1715
} else {
1651
- if ( defaultExport ) {
1716
+ if ( defaultExport || definedOptions ) {
1652
1717
// without TS, can't rely on rest spread, so we use Object.assign
1653
1718
// export default Object.assign(__default__, { ... })
1654
1719
s . prependLeft (
1655
1720
startOffset ,
1656
- `\nexport default /*#__PURE__*/Object.assign(${ DEFAULT_VAR } , {${ runtimeOptions } \n ` +
1721
+ `\nexport default /*#__PURE__*/Object.assign(${
1722
+ defaultExport ? `${ DEFAULT_VAR } , ` : ''
1723
+ } ${ definedOptions ? `${ definedOptions } , ` : '' } {${ runtimeOptions } \n ` +
1657
1724
`${ hasAwait ? `async ` : `` } setup(${ args } ) {\n${ exposeCall } `
1658
1725
)
1659
1726
s . appendRight ( endOffset , `})` )
0 commit comments