@vue/compiler-sfc 3.2.41 → 3.2.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -119,7 +119,8 @@ function genVarName(id, raw, isProd) {
119
119
  return hashSum(id + raw);
120
120
  }
121
121
  else {
122
- return `${id}-${raw.replace(/([^\w-])/g, '_')}`;
122
+ // escape ASCII Punctuation & Symbols
123
+ return `${id}-${raw.replace(/[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, s => `\\${s}`)}`;
123
124
  }
124
125
  }
125
126
  function normalizeExpression(exp) {
@@ -3537,7 +3538,6 @@ function compileScript(sfc, options) {
3537
3538
  const bindingMetadata = {};
3538
3539
  const helperImports = new Set();
3539
3540
  const userImports = Object.create(null);
3540
- const userImportAlias = Object.create(null);
3541
3541
  const scriptBindings = Object.create(null);
3542
3542
  const setupBindings = Object.create(null);
3543
3543
  let defaultExport;
@@ -3588,10 +3588,24 @@ function compileScript(sfc, options) {
3588
3588
  function error(msg, node, end = node.end + startOffset) {
3589
3589
  throw new Error(`[@vue/compiler-sfc] ${msg}\n\n${sfc.filename}\n${shared.generateCodeFrame(source, node.start + startOffset, end)}`);
3590
3590
  }
3591
- function registerUserImport(source, local, imported, isType, isFromSetup, needTemplateUsageCheck) {
3592
- if (source === 'vue' && imported) {
3593
- userImportAlias[imported] = local;
3591
+ function hoistNode(node) {
3592
+ const start = node.start + startOffset;
3593
+ let end = node.end + startOffset;
3594
+ // locate comment
3595
+ if (node.trailingComments && node.trailingComments.length > 0) {
3596
+ const lastCommentNode = node.trailingComments[node.trailingComments.length - 1];
3597
+ end = lastCommentNode.end + startOffset;
3598
+ }
3599
+ // locate the end of whitespace between this statement and the next
3600
+ while (end <= source.length) {
3601
+ if (!/\s/.test(source.charAt(end))) {
3602
+ break;
3603
+ }
3604
+ end++;
3594
3605
  }
3606
+ s.move(start, end, 0);
3607
+ }
3608
+ function registerUserImport(source, local, imported, isType, isFromSetup, needTemplateUsageCheck) {
3595
3609
  // template usage check is only needed in non-inline mode, so we can skip
3596
3610
  // the work if inlineTemplate is true.
3597
3611
  let isUsedInTemplate = needTemplateUsageCheck;
@@ -3605,6 +3619,7 @@ function compileScript(sfc, options) {
3605
3619
  userImports[local] = {
3606
3620
  isType,
3607
3621
  imported: imported || 'default',
3622
+ local,
3608
3623
  source,
3609
3624
  isFromSetup,
3610
3625
  isUsedInTemplate
@@ -3638,12 +3653,10 @@ function compileScript(sfc, options) {
3638
3653
  // props destructure - handle compilation sugar
3639
3654
  for (const prop of declId.properties) {
3640
3655
  if (prop.type === 'ObjectProperty') {
3641
- if (prop.computed) {
3656
+ const propKey = resolveObjectKey(prop.key, prop.computed);
3657
+ if (!propKey) {
3642
3658
  error(`${DEFINE_PROPS}() destructure cannot use computed key.`, prop.key);
3643
3659
  }
3644
- const propKey = prop.key.type === 'StringLiteral'
3645
- ? prop.key.value
3646
- : prop.key.name;
3647
3660
  if (prop.value.type === 'AssignmentPattern') {
3648
3661
  // default value { foo = 123 }
3649
3662
  const { left, right } = prop.value;
@@ -3724,10 +3737,67 @@ function compileScript(sfc, options) {
3724
3737
  }
3725
3738
  }
3726
3739
  if (declId) {
3727
- emitIdentifier = scriptSetup.content.slice(declId.start, declId.end);
3740
+ emitIdentifier =
3741
+ declId.type === 'Identifier'
3742
+ ? declId.name
3743
+ : scriptSetup.content.slice(declId.start, declId.end);
3728
3744
  }
3729
3745
  return true;
3730
3746
  }
3747
+ function getAstBody() {
3748
+ return scriptAst
3749
+ ? [...scriptSetupAst.body, ...scriptAst.body]
3750
+ : scriptSetupAst.body;
3751
+ }
3752
+ function resolveExtendsType(node, qualifier, cache = []) {
3753
+ if (node.type === 'TSInterfaceDeclaration' && node.extends) {
3754
+ node.extends.forEach(extend => {
3755
+ if (extend.type === 'TSExpressionWithTypeArguments' &&
3756
+ extend.expression.type === 'Identifier') {
3757
+ const body = getAstBody();
3758
+ for (const node of body) {
3759
+ const qualified = isQualifiedType(node, qualifier, extend.expression.name);
3760
+ if (qualified) {
3761
+ cache.push(qualified);
3762
+ resolveExtendsType(node, qualifier, cache);
3763
+ return cache;
3764
+ }
3765
+ }
3766
+ }
3767
+ });
3768
+ }
3769
+ return cache;
3770
+ }
3771
+ function isQualifiedType(node, qualifier, refName) {
3772
+ if (node.type === 'TSInterfaceDeclaration' && node.id.name === refName) {
3773
+ return node.body;
3774
+ }
3775
+ else if (node.type === 'TSTypeAliasDeclaration' &&
3776
+ node.id.name === refName &&
3777
+ qualifier(node.typeAnnotation)) {
3778
+ return node.typeAnnotation;
3779
+ }
3780
+ else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
3781
+ return isQualifiedType(node.declaration, qualifier, refName);
3782
+ }
3783
+ }
3784
+ // filter all extends types to keep the override declaration
3785
+ function filterExtendsType(extendsTypes, bodies) {
3786
+ extendsTypes.forEach(extend => {
3787
+ const body = extend.body;
3788
+ body.forEach(newBody => {
3789
+ if (newBody.type === 'TSPropertySignature' &&
3790
+ newBody.key.type === 'Identifier') {
3791
+ const name = newBody.key.name;
3792
+ const hasOverride = bodies.some(seenBody => seenBody.type === 'TSPropertySignature' &&
3793
+ seenBody.key.type === 'Identifier' &&
3794
+ seenBody.key.name === name);
3795
+ if (!hasOverride)
3796
+ bodies.push(newBody);
3797
+ }
3798
+ });
3799
+ });
3800
+ }
3731
3801
  function resolveQualifiedType(node, qualifier) {
3732
3802
  if (qualifier(node)) {
3733
3803
  return node;
@@ -3735,26 +3805,16 @@ function compileScript(sfc, options) {
3735
3805
  if (node.type === 'TSTypeReference' &&
3736
3806
  node.typeName.type === 'Identifier') {
3737
3807
  const refName = node.typeName.name;
3738
- const isQualifiedType = (node) => {
3739
- if (node.type === 'TSInterfaceDeclaration' &&
3740
- node.id.name === refName) {
3741
- return node.body;
3742
- }
3743
- else if (node.type === 'TSTypeAliasDeclaration' &&
3744
- node.id.name === refName &&
3745
- qualifier(node.typeAnnotation)) {
3746
- return node.typeAnnotation;
3747
- }
3748
- else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
3749
- return isQualifiedType(node.declaration);
3750
- }
3751
- };
3752
- const body = scriptAst
3753
- ? [...scriptSetupAst.body, ...scriptAst.body]
3754
- : scriptSetupAst.body;
3808
+ const body = getAstBody();
3755
3809
  for (const node of body) {
3756
- const qualified = isQualifiedType(node);
3810
+ let qualified = isQualifiedType(node, qualifier, refName);
3757
3811
  if (qualified) {
3812
+ const extendsTypes = resolveExtendsType(node, qualifier);
3813
+ if (extendsTypes.length) {
3814
+ const bodies = [...qualified.body];
3815
+ filterExtendsType(extendsTypes, bodies);
3816
+ qualified.body = bodies;
3817
+ }
3758
3818
  return qualified;
3759
3819
  }
3760
3820
  }
@@ -3818,7 +3878,8 @@ function compileScript(sfc, options) {
3818
3878
  function hasStaticWithDefaults() {
3819
3879
  return (propsRuntimeDefaults &&
3820
3880
  propsRuntimeDefaults.type === 'ObjectExpression' &&
3821
- propsRuntimeDefaults.properties.every(node => (node.type === 'ObjectProperty' && !node.computed) ||
3881
+ propsRuntimeDefaults.properties.every(node => (node.type === 'ObjectProperty' &&
3882
+ (!node.computed || node.key.type.endsWith('Literal'))) ||
3822
3883
  node.type === 'ObjectMethod'));
3823
3884
  }
3824
3885
  function genRuntimeProps(props) {
@@ -3837,14 +3898,18 @@ function compileScript(sfc, options) {
3837
3898
  defaultString = `default: ${destructured}`;
3838
3899
  }
3839
3900
  else if (hasStaticDefaults) {
3840
- const prop = propsRuntimeDefaults.properties.find((node) => node.key.name === key);
3901
+ const prop = propsRuntimeDefaults.properties.find(node => {
3902
+ if (node.type === 'SpreadElement')
3903
+ return false;
3904
+ return resolveObjectKey(node.key, node.computed) === key;
3905
+ });
3841
3906
  if (prop) {
3842
3907
  if (prop.type === 'ObjectProperty') {
3843
3908
  // prop has corresponding static default value
3844
3909
  defaultString = `default: ${scriptSetupSource.slice(prop.value.start, prop.value.end)}`;
3845
3910
  }
3846
3911
  else {
3847
- defaultString = `default() ${scriptSetupSource.slice(prop.body.start, prop.body.end)}`;
3912
+ defaultString = `${prop.async ? 'async ' : ''}${prop.kind !== 'method' ? `${prop.kind} ` : ''}default() ${scriptSetupSource.slice(prop.body.start, prop.body.end)}`;
3848
3913
  }
3849
3914
  }
3850
3915
  }
@@ -3887,7 +3952,12 @@ function compileScript(sfc, options) {
3887
3952
  m.type === 'TSMethodSignature') &&
3888
3953
  m.typeAnnotation &&
3889
3954
  m.key.type === 'Identifier') {
3890
- if (propsRuntimeDefaults.properties.some((p) => p.key.name === m.key.name)) {
3955
+ if (propsRuntimeDefaults.properties.some(p => {
3956
+ if (p.type === 'SpreadElement')
3957
+ return false;
3958
+ return (resolveObjectKey(p.key, p.computed) ===
3959
+ m.key.name);
3960
+ })) {
3891
3961
  res +=
3892
3962
  m.key.name +
3893
3963
  (m.type === 'TSMethodSignature' ? '()' : '') +
@@ -3906,13 +3976,22 @@ function compileScript(sfc, options) {
3906
3976
  return scriptSetupSource.slice(node.start, node.end);
3907
3977
  }
3908
3978
  }
3909
- // 1. process normal <script> first if it exists
3910
- let scriptAst;
3911
- if (script) {
3912
- scriptAst = parse(script.content, {
3979
+ // 0. parse both <script> and <script setup> blocks
3980
+ const scriptAst = script &&
3981
+ parse(script.content, {
3913
3982
  plugins,
3914
3983
  sourceType: 'module'
3915
3984
  }, scriptStartOffset);
3985
+ const scriptSetupAst = parse(scriptSetup.content, {
3986
+ plugins: [
3987
+ ...plugins,
3988
+ // allow top level await but only inside <script setup>
3989
+ 'topLevelAwait'
3990
+ ],
3991
+ sourceType: 'module'
3992
+ }, startOffset);
3993
+ // 1.1 walk import delcarations of <script>
3994
+ if (scriptAst) {
3916
3995
  for (const node of scriptAst.body) {
3917
3996
  if (node.type === 'ImportDeclaration') {
3918
3997
  // record imports for dedupe
@@ -3925,7 +4004,75 @@ function compileScript(sfc, options) {
3925
4004
  specifier.importKind === 'type'), false, !options.inlineTemplate);
3926
4005
  }
3927
4006
  }
3928
- else if (node.type === 'ExportDefaultDeclaration') {
4007
+ }
4008
+ }
4009
+ // 1.2 walk import declarations of <script setup>
4010
+ for (const node of scriptSetupAst.body) {
4011
+ if (node.type === 'ImportDeclaration') {
4012
+ // import declarations are moved to top
4013
+ hoistNode(node);
4014
+ // dedupe imports
4015
+ let removed = 0;
4016
+ const removeSpecifier = (i) => {
4017
+ const removeLeft = i > removed;
4018
+ removed++;
4019
+ const current = node.specifiers[i];
4020
+ const next = node.specifiers[i + 1];
4021
+ s.remove(removeLeft
4022
+ ? node.specifiers[i - 1].end + startOffset
4023
+ : current.start + startOffset, next && !removeLeft
4024
+ ? next.start + startOffset
4025
+ : current.end + startOffset);
4026
+ };
4027
+ for (let i = 0; i < node.specifiers.length; i++) {
4028
+ const specifier = node.specifiers[i];
4029
+ const local = specifier.local.name;
4030
+ let imported = specifier.type === 'ImportSpecifier' &&
4031
+ specifier.imported.type === 'Identifier' &&
4032
+ specifier.imported.name;
4033
+ if (specifier.type === 'ImportNamespaceSpecifier') {
4034
+ imported = '*';
4035
+ }
4036
+ const source = node.source.value;
4037
+ const existing = userImports[local];
4038
+ if (source === 'vue' &&
4039
+ (imported === DEFINE_PROPS ||
4040
+ imported === DEFINE_EMITS ||
4041
+ imported === DEFINE_EXPOSE)) {
4042
+ warnOnce(`\`${imported}\` is a compiler macro and no longer needs to be imported.`);
4043
+ removeSpecifier(i);
4044
+ }
4045
+ else if (existing) {
4046
+ if (existing.source === source && existing.imported === imported) {
4047
+ // already imported in <script setup>, dedupe
4048
+ removeSpecifier(i);
4049
+ }
4050
+ else {
4051
+ error(`different imports aliased to same local name.`, specifier);
4052
+ }
4053
+ }
4054
+ else {
4055
+ registerUserImport(source, local, imported, node.importKind === 'type' ||
4056
+ (specifier.type === 'ImportSpecifier' &&
4057
+ specifier.importKind === 'type'), true, !options.inlineTemplate);
4058
+ }
4059
+ }
4060
+ if (node.specifiers.length && removed === node.specifiers.length) {
4061
+ s.remove(node.start + startOffset, node.end + startOffset);
4062
+ }
4063
+ }
4064
+ }
4065
+ // 1.3 resolve possible user import alias of `ref` and `reactive`
4066
+ const vueImportAliases = {};
4067
+ for (const key in userImports) {
4068
+ const { source, imported, local } = userImports[key];
4069
+ if (source === 'vue')
4070
+ vueImportAliases[imported] = local;
4071
+ }
4072
+ // 2.1 process normal <script> body
4073
+ if (script && scriptAst) {
4074
+ for (const node of scriptAst.body) {
4075
+ if (node.type === 'ExportDefaultDeclaration') {
3929
4076
  // export default
3930
4077
  defaultExport = node;
3931
4078
  // check if user has manually specified `name` or 'render` option in
@@ -3985,7 +4132,7 @@ function compileScript(sfc, options) {
3985
4132
  }
3986
4133
  }
3987
4134
  if (node.declaration) {
3988
- walkDeclaration(node.declaration, scriptBindings, userImportAlias);
4135
+ walkDeclaration(node.declaration, scriptBindings, vueImportAliases);
3989
4136
  }
3990
4137
  }
3991
4138
  else if ((node.type === 'VariableDeclaration' ||
@@ -3993,7 +4140,7 @@ function compileScript(sfc, options) {
3993
4140
  node.type === 'ClassDeclaration' ||
3994
4141
  node.type === 'TSEnumDeclaration') &&
3995
4142
  !node.declare) {
3996
- walkDeclaration(node, scriptBindings, userImportAlias);
4143
+ walkDeclaration(node, scriptBindings, vueImportAliases);
3997
4144
  }
3998
4145
  }
3999
4146
  // apply reactivity transform
@@ -4015,31 +4162,10 @@ function compileScript(sfc, options) {
4015
4162
  s.move(scriptStartOffset, scriptEndOffset, 0);
4016
4163
  }
4017
4164
  }
4018
- // 2. parse <script setup> and walk over top level statements
4019
- const scriptSetupAst = parse(scriptSetup.content, {
4020
- plugins: [
4021
- ...plugins,
4022
- // allow top level await but only inside <script setup>
4023
- 'topLevelAwait'
4024
- ],
4025
- sourceType: 'module'
4026
- }, startOffset);
4165
+ // 2.2 process <script setup> body
4027
4166
  for (const node of scriptSetupAst.body) {
4028
- const start = node.start + startOffset;
4029
- let end = node.end + startOffset;
4030
- // locate comment
4031
- if (node.trailingComments && node.trailingComments.length > 0) {
4032
- const lastCommentNode = node.trailingComments[node.trailingComments.length - 1];
4033
- end = lastCommentNode.end + startOffset;
4034
- }
4035
- // locate the end of whitespace between this statement and the next
4036
- while (end <= source.length) {
4037
- if (!/\s/.test(source.charAt(end))) {
4038
- break;
4039
- }
4040
- end++;
4041
- }
4042
4167
  // (Dropped) `ref: x` bindings
4168
+ // TODO remove when out of experimental
4043
4169
  if (node.type === 'LabeledStatement' &&
4044
4170
  node.label.name === 'ref' &&
4045
4171
  node.body.type === 'ExpressionStatement') {
@@ -4047,59 +4173,6 @@ function compileScript(sfc, options) {
4047
4173
  `has been dropped based on community feedback. Please check out ` +
4048
4174
  `the new proposal at https://github.com/vuejs/rfcs/discussions/369`, node);
4049
4175
  }
4050
- if (node.type === 'ImportDeclaration') {
4051
- // import declarations are moved to top
4052
- s.move(start, end, 0);
4053
- // dedupe imports
4054
- let removed = 0;
4055
- const removeSpecifier = (i) => {
4056
- const removeLeft = i > removed;
4057
- removed++;
4058
- const current = node.specifiers[i];
4059
- const next = node.specifiers[i + 1];
4060
- s.remove(removeLeft
4061
- ? node.specifiers[i - 1].end + startOffset
4062
- : current.start + startOffset, next && !removeLeft
4063
- ? next.start + startOffset
4064
- : current.end + startOffset);
4065
- };
4066
- for (let i = 0; i < node.specifiers.length; i++) {
4067
- const specifier = node.specifiers[i];
4068
- const local = specifier.local.name;
4069
- let imported = specifier.type === 'ImportSpecifier' &&
4070
- specifier.imported.type === 'Identifier' &&
4071
- specifier.imported.name;
4072
- if (specifier.type === 'ImportNamespaceSpecifier') {
4073
- imported = '*';
4074
- }
4075
- const source = node.source.value;
4076
- const existing = userImports[local];
4077
- if (source === 'vue' &&
4078
- (imported === DEFINE_PROPS ||
4079
- imported === DEFINE_EMITS ||
4080
- imported === DEFINE_EXPOSE)) {
4081
- warnOnce(`\`${imported}\` is a compiler macro and no longer needs to be imported.`);
4082
- removeSpecifier(i);
4083
- }
4084
- else if (existing) {
4085
- if (existing.source === source && existing.imported === imported) {
4086
- // already imported in <script setup>, dedupe
4087
- removeSpecifier(i);
4088
- }
4089
- else {
4090
- error(`different imports aliased to same local name.`, specifier);
4091
- }
4092
- }
4093
- else {
4094
- registerUserImport(source, local, imported, node.importKind === 'type' ||
4095
- (specifier.type === 'ImportSpecifier' &&
4096
- specifier.importKind === 'type'), true, !options.inlineTemplate);
4097
- }
4098
- }
4099
- if (node.specifiers.length && removed === node.specifiers.length) {
4100
- s.remove(node.start + startOffset, node.end + startOffset);
4101
- }
4102
- }
4103
4176
  if (node.type === 'ExpressionStatement') {
4104
4177
  // process `defineProps` and `defineEmit(s)` calls
4105
4178
  if (processDefineProps(node.expression) ||
@@ -4130,12 +4203,12 @@ function compileScript(sfc, options) {
4130
4203
  else {
4131
4204
  let start = decl.start + startOffset;
4132
4205
  let end = decl.end + startOffset;
4133
- if (i < total - 1) {
4134
- // not the last one, locate the start of the next
4206
+ if (i === 0) {
4207
+ // first one, locate the start of the next
4135
4208
  end = node.declarations[i + 1].start + startOffset;
4136
4209
  }
4137
4210
  else {
4138
- // last one, locate the end of the prev
4211
+ // not first one, locate the end of the prev
4139
4212
  start = node.declarations[i - 1].end + startOffset;
4140
4213
  }
4141
4214
  s.remove(start, end);
@@ -4150,7 +4223,7 @@ function compileScript(sfc, options) {
4150
4223
  node.type === 'FunctionDeclaration' ||
4151
4224
  node.type === 'ClassDeclaration') &&
4152
4225
  !node.declare) {
4153
- walkDeclaration(node, setupBindings, userImportAlias);
4226
+ walkDeclaration(node, setupBindings, vueImportAliases);
4154
4227
  }
4155
4228
  // walk statements & named exports / variable declarations for top level
4156
4229
  // await
@@ -4204,7 +4277,7 @@ function compileScript(sfc, options) {
4204
4277
  node.exportKind === 'type') ||
4205
4278
  (node.type === 'VariableDeclaration' && node.declare)) {
4206
4279
  recordType(node, declaredTypes);
4207
- s.move(start, end, 0);
4280
+ hoistNode(node);
4208
4281
  }
4209
4282
  }
4210
4283
  }
@@ -4321,10 +4394,10 @@ function compileScript(sfc, options) {
4321
4394
  // we use a default __props so that template expressions referencing props
4322
4395
  // can use it directly
4323
4396
  if (propsIdentifier) {
4324
- s.prependLeft(startOffset, `\nconst ${propsIdentifier} = __props${propsTypeDecl ? ` as ${genSetupPropsType(propsTypeDecl)}` : ``}\n`);
4397
+ s.prependLeft(startOffset, `\nconst ${propsIdentifier} = __props${propsTypeDecl ? ` as ${genSetupPropsType(propsTypeDecl)}` : ``};\n`);
4325
4398
  }
4326
4399
  if (propsDestructureRestId) {
4327
- s.prependLeft(startOffset, `\nconst ${propsDestructureRestId} = ${helper(`createPropsRestProxy`)}(__props, ${JSON.stringify(Object.keys(propsDestructuredBindings))})\n`);
4400
+ s.prependLeft(startOffset, `\nconst ${propsDestructureRestId} = ${helper(`createPropsRestProxy`)}(__props, ${JSON.stringify(Object.keys(propsDestructuredBindings))});\n`);
4328
4401
  }
4329
4402
  // inject temp variables for async context preservation
4330
4403
  if (hasAwait) {
@@ -4519,7 +4592,7 @@ function compileScript(sfc, options) {
4519
4592
  function registerBinding(bindings, node, type) {
4520
4593
  bindings[node.name] = type;
4521
4594
  }
4522
- function walkDeclaration(node, bindings, userImportAlias) {
4595
+ function walkDeclaration(node, bindings, userImportAliases) {
4523
4596
  if (node.type === 'VariableDeclaration') {
4524
4597
  const isConst = node.kind === 'const';
4525
4598
  // export const foo = ...
@@ -4528,7 +4601,7 @@ function walkDeclaration(node, bindings, userImportAlias) {
4528
4601
  isCallOf(init, c => c === DEFINE_PROPS || c === DEFINE_EMITS || c === WITH_DEFAULTS));
4529
4602
  if (id.type === 'Identifier') {
4530
4603
  let bindingType;
4531
- const userReactiveBinding = userImportAlias['reactive'] || 'reactive';
4604
+ const userReactiveBinding = userImportAliases['reactive'];
4532
4605
  if (isCallOf(init, userReactiveBinding)) {
4533
4606
  // treat reactive() calls as let since it's meant to be mutable
4534
4607
  bindingType = isConst
@@ -4545,7 +4618,7 @@ function walkDeclaration(node, bindings, userImportAlias) {
4545
4618
  : "setup-const" /* BindingTypes.SETUP_CONST */;
4546
4619
  }
4547
4620
  else if (isConst) {
4548
- if (isCallOf(init, userImportAlias['ref'] || 'ref')) {
4621
+ if (isCallOf(init, userImportAliases['ref'])) {
4549
4622
  bindingType = "setup-ref" /* BindingTypes.SETUP_REF */;
4550
4623
  }
4551
4624
  else {
@@ -4793,6 +4866,7 @@ function genRuntimeEmits(emits) {
4793
4866
  }
4794
4867
  function isCallOf(node, test) {
4795
4868
  return !!(node &&
4869
+ test &&
4796
4870
  node.type === 'CallExpression' &&
4797
4871
  node.callee.type === 'Identifier' &&
4798
4872
  (typeof test === 'string'
@@ -4903,15 +4977,11 @@ function analyzeBindingsFromOptions(node) {
4903
4977
  function getObjectExpressionKeys(node) {
4904
4978
  const keys = [];
4905
4979
  for (const prop of node.properties) {
4906
- if ((prop.type === 'ObjectProperty' || prop.type === 'ObjectMethod') &&
4907
- !prop.computed) {
4908
- if (prop.key.type === 'Identifier') {
4909
- keys.push(prop.key.name);
4910
- }
4911
- else if (prop.key.type === 'StringLiteral') {
4912
- keys.push(prop.key.value);
4913
- }
4914
- }
4980
+ if (prop.type === 'SpreadElement')
4981
+ continue;
4982
+ const key = resolveObjectKey(prop.key, prop.computed);
4983
+ if (key)
4984
+ keys.push(String(key));
4915
4985
  }
4916
4986
  return keys;
4917
4987
  }
@@ -5036,6 +5106,17 @@ function hmrShouldReload(prevImports, next) {
5036
5106
  }
5037
5107
  return false;
5038
5108
  }
5109
+ function resolveObjectKey(node, computed) {
5110
+ switch (node.type) {
5111
+ case 'StringLiteral':
5112
+ case 'NumericLiteral':
5113
+ return node.value;
5114
+ case 'Identifier':
5115
+ if (!computed)
5116
+ return node.name;
5117
+ }
5118
+ return undefined;
5119
+ }
5039
5120
 
5040
5121
  const DEFAULT_FILENAME = 'anonymous.vue';
5041
5122
  const sourceToSFC = createCache();
@@ -5140,6 +5221,9 @@ function parse(source, { sourceMap = true, filename = DEFAULT_FILENAME, sourceRo
5140
5221
  break;
5141
5222
  }
5142
5223
  });
5224
+ if (!descriptor.template && !descriptor.script && !descriptor.scriptSetup) {
5225
+ errors.push(new SyntaxError(`At least one <template> or <script> is required in a single file component.`));
5226
+ }
5143
5227
  if (descriptor.scriptSetup) {
5144
5228
  if (descriptor.scriptSetup.src) {
5145
5229
  errors.push(new SyntaxError(`<script setup> cannot use the "src" attribute because ` +
@@ -17,6 +17,7 @@ import { Result } from 'postcss';
17
17
  import { RootNode } from '@vue/compiler-core';
18
18
  import { shouldTransform as shouldTransformRef } from '@vue/reactivity-transform';
19
19
  import { SourceLocation } from '@vue/compiler-core';
20
+ import { Statement } from '@babel/types';
20
21
  import { transform as transformRef } from '@vue/reactivity-transform';
21
22
  import { transformAST as transformRefAST } from '@vue/reactivity-transform';
22
23
  import { walkIdentifiers } from '@vue/compiler-core';
@@ -79,6 +80,7 @@ export { generateCodeFrame }
79
80
  declare interface ImportBinding {
80
81
  isType: boolean;
81
82
  imported: string;
83
+ local: string;
82
84
  source: string;
83
85
  isFromSetup: boolean;
84
86
  isUsedInTemplate: boolean;
@@ -160,14 +162,8 @@ export declare interface SFCScriptBlock extends SFCBlock {
160
162
  setup?: string | boolean;
161
163
  bindings?: BindingMetadata;
162
164
  imports?: Record<string, ImportBinding>;
163
- /**
164
- * import('\@babel/types').Statement
165
- */
166
- scriptAst?: any[];
167
- /**
168
- * import('\@babel/types').Statement
169
- */
170
- scriptSetupAst?: any[];
165
+ scriptAst?: Statement[];
166
+ scriptSetupAst?: Statement[];
171
167
  }
172
168
 
173
169
  export declare interface SFCScriptCompileOptions {