vue 2.6.7 → 2.6.11

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.
Files changed (45) hide show
  1. package/README.md +72 -52
  2. package/dist/README.md +1 -1
  3. package/dist/vue.common.dev.js +109 -51
  4. package/dist/vue.common.prod.js +2 -2
  5. package/dist/vue.esm.browser.js +109 -51
  6. package/dist/vue.esm.browser.min.js +2 -2
  7. package/dist/vue.esm.js +109 -51
  8. package/dist/vue.js +109 -51
  9. package/dist/vue.min.js +2 -2
  10. package/dist/vue.runtime.common.dev.js +80 -38
  11. package/dist/vue.runtime.common.prod.js +2 -2
  12. package/dist/vue.runtime.esm.js +80 -38
  13. package/dist/vue.runtime.js +80 -38
  14. package/dist/vue.runtime.min.js +2 -2
  15. package/package.json +4 -4
  16. package/src/compiler/codegen/events.js +1 -1
  17. package/src/compiler/codegen/index.js +1 -1
  18. package/src/compiler/error-detector.js +18 -3
  19. package/src/compiler/parser/html-parser.js +5 -5
  20. package/src/compiler/parser/index.js +7 -6
  21. package/src/core/instance/proxy.js +1 -1
  22. package/src/core/instance/render-helpers/bind-dynamic-keys.js +1 -1
  23. package/src/core/instance/render-helpers/bind-object-props.js +5 -3
  24. package/src/core/instance/render.js +1 -1
  25. package/src/core/observer/scheduler.js +17 -6
  26. package/src/core/util/env.js +1 -2
  27. package/src/core/util/error.js +4 -3
  28. package/src/core/util/lang.js +2 -2
  29. package/src/core/util/next-tick.js +1 -1
  30. package/src/core/util/options.js +2 -2
  31. package/src/core/vdom/create-element.js +6 -0
  32. package/src/core/vdom/helpers/normalize-scoped-slots.js +9 -4
  33. package/src/core/vdom/helpers/resolve-async-component.js +25 -8
  34. package/src/core/vdom/patch.js +4 -4
  35. package/src/platforms/web/compiler/modules/model.js +1 -1
  36. package/src/platforms/web/runtime/modules/dom-props.js +2 -1
  37. package/src/platforms/web/runtime/modules/events.js +4 -2
  38. package/src/platforms/web/runtime/modules/transition.js +1 -1
  39. package/src/server/template-renderer/create-async-file-mapper.js +2 -2
  40. package/src/server/write.js +1 -1
  41. package/types/index.d.ts +1 -2
  42. package/types/options.d.ts +3 -3
  43. package/types/umd.d.ts +48 -0
  44. package/types/vnode.d.ts +6 -2
  45. package/types/vue.d.ts +3 -3
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vue.js v2.6.7
2
+ * Vue.js v2.6.11
3
3
  * (c) 2014-2019 Evan You
4
4
  * Released under the MIT License.
5
5
  */
@@ -475,7 +475,7 @@ var config = ({
475
475
  * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname
476
476
  * skipping \u10000-\uEFFFF due to it freezing up PhantomJS
477
477
  */
478
- const unicodeLetters = 'a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD';
478
+ const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/;
479
479
 
480
480
  /**
481
481
  * Check if a string starts with $ or _
@@ -500,7 +500,7 @@ function def (obj, key, val, enumerable) {
500
500
  /**
501
501
  * Parse simple path.
502
502
  */
503
- const bailRE = new RegExp(`[^${unicodeLetters}.$_\\d]`);
503
+ const bailRE = new RegExp(`[^${unicodeRegExp.source}.$_\\d]`);
504
504
  function parsePath (path) {
505
505
  if (bailRE.test(path)) {
506
506
  return
@@ -1440,7 +1440,7 @@ function checkComponents (options) {
1440
1440
  }
1441
1441
 
1442
1442
  function validateComponentName (name) {
1443
- if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_${unicodeLetters}]*$`).test(name)) {
1443
+ if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_${unicodeRegExp.source}]*$`).test(name)) {
1444
1444
  warn(
1445
1445
  'Invalid component name: "' + name + '". Component names ' +
1446
1446
  'should conform to valid custom element name in html5 specification.'
@@ -1888,10 +1888,11 @@ function invokeWithErrorHandling (
1888
1888
  let res;
1889
1889
  try {
1890
1890
  res = args ? handler.apply(context, args) : handler.call(context);
1891
- if (res && !res._isVue && isPromise(res)) {
1891
+ if (res && !res._isVue && isPromise(res) && !res._handled) {
1892
+ res.catch(e => handleError(e, vm, info + ` (Promise/async)`));
1892
1893
  // issue #9511
1893
- // reassign to res to avoid catch triggering multiple times when nested calls
1894
- res = res.catch(e => handleError(e, vm, info + ` (Promise/async)`));
1894
+ // avoid catch triggering multiple times when nested calls
1895
+ res._handled = true;
1895
1896
  }
1896
1897
  } catch (e) {
1897
1898
  handleError(e, vm, info);
@@ -1995,7 +1996,7 @@ if (typeof Promise !== 'undefined' && isNative(Promise)) {
1995
1996
  isUsingMicroTask = true;
1996
1997
  } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
1997
1998
  // Fallback to setImmediate.
1998
- // Techinically it leverages the (macro) task queue,
1999
+ // Technically it leverages the (macro) task queue,
1999
2000
  // but it is still a better choice than setTimeout.
2000
2001
  timerFunc = () => {
2001
2002
  setImmediate(flushCallbacks);
@@ -2084,7 +2085,7 @@ let initProxy;
2084
2085
  warn(
2085
2086
  `Property "${key}" must be accessed with "$data.${key}" because ` +
2086
2087
  'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
2087
- 'prevent conflicts with Vue internals' +
2088
+ 'prevent conflicts with Vue internals. ' +
2088
2089
  'See: https://vuejs.org/v2/api/#data',
2089
2090
  target
2090
2091
  );
@@ -2571,7 +2572,8 @@ function normalizeScopedSlots (
2571
2572
  prevSlots
2572
2573
  ) {
2573
2574
  let res;
2574
- const isStable = slots ? !!slots.$stable : true;
2575
+ const hasNormalSlots = Object.keys(normalSlots).length > 0;
2576
+ const isStable = slots ? !!slots.$stable : !hasNormalSlots;
2575
2577
  const key = slots && slots.$key;
2576
2578
  if (!slots) {
2577
2579
  res = {};
@@ -2583,7 +2585,8 @@ function normalizeScopedSlots (
2583
2585
  prevSlots &&
2584
2586
  prevSlots !== emptyObject &&
2585
2587
  key === prevSlots.$key &&
2586
- Object.keys(normalSlots).length === 0
2588
+ !hasNormalSlots &&
2589
+ !prevSlots.$hasNormal
2587
2590
  ) {
2588
2591
  // fast path 2: stable scoped slots w/ no normal slots to proxy,
2589
2592
  // only need to normalize once
@@ -2609,6 +2612,7 @@ function normalizeScopedSlots (
2609
2612
  }
2610
2613
  def(res, '$stable', isStable);
2611
2614
  def(res, '$key', key);
2615
+ def(res, '$hasNormal', hasNormalSlots);
2612
2616
  return res
2613
2617
  }
2614
2618
 
@@ -2618,8 +2622,10 @@ function normalizeScopedSlot(normalSlots, key, fn) {
2618
2622
  res = res && typeof res === 'object' && !Array.isArray(res)
2619
2623
  ? [res] // single vnode
2620
2624
  : normalizeChildren(res);
2621
- return res && res.length === 0
2622
- ? undefined
2625
+ return res && (
2626
+ res.length === 0 ||
2627
+ (res.length === 1 && res[0].isComment) // #9658
2628
+ ) ? undefined
2623
2629
  : res
2624
2630
  };
2625
2631
  // this is a slot using the new v-slot syntax without scope. although it is
@@ -2799,12 +2805,13 @@ function bindObjectProps (
2799
2805
  : data.attrs || (data.attrs = {});
2800
2806
  }
2801
2807
  const camelizedKey = camelize(key);
2802
- if (!(key in hash) && !(camelizedKey in hash)) {
2808
+ const hyphenatedKey = hyphenate(key);
2809
+ if (!(camelizedKey in hash) && !(hyphenatedKey in hash)) {
2803
2810
  hash[key] = value[key];
2804
2811
 
2805
2812
  if (isSync) {
2806
2813
  const on = data.on || (data.on = {});
2807
- on[`update:${camelizedKey}`] = function ($event) {
2814
+ on[`update:${key}`] = function ($event) {
2808
2815
  value[key] = $event;
2809
2816
  };
2810
2817
  }
@@ -2933,7 +2940,7 @@ function bindDynamicKeys (baseObj, values) {
2933
2940
  if (typeof key === 'string' && key) {
2934
2941
  baseObj[values[i]] = values[i + 1];
2935
2942
  } else if (key !== '' && key !== null) {
2936
- // null is a speical value for explicitly removing a binding
2943
+ // null is a special value for explicitly removing a binding
2937
2944
  warn(
2938
2945
  `Invalid value for dynamic directive argument (expected string or null): ${key}`,
2939
2946
  this
@@ -3425,6 +3432,12 @@ function _createElement (
3425
3432
  ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag);
3426
3433
  if (config.isReservedTag(tag)) {
3427
3434
  // platform built-in elements
3435
+ if (isDef(data) && isDef(data.nativeOn)) {
3436
+ warn(
3437
+ `The .native modifier for v-on is only valid on components but it was used on <${tag}>.`,
3438
+ context
3439
+ );
3440
+ }
3428
3441
  vnode = new VNode(
3429
3442
  config.parsePlatformTagName(tag), data, children,
3430
3443
  undefined, undefined, context
@@ -3548,7 +3561,7 @@ function renderMixin (Vue) {
3548
3561
  // render self
3549
3562
  let vnode;
3550
3563
  try {
3551
- // There's no need to maintain a stack becaues all render fns are called
3564
+ // There's no need to maintain a stack because all render fns are called
3552
3565
  // separately from one another. Nested component's render fns are called
3553
3566
  // when parent component is patched.
3554
3567
  currentRenderingInstance = vm;
@@ -3631,17 +3644,23 @@ function resolveAsyncComponent (
3631
3644
  return factory.resolved
3632
3645
  }
3633
3646
 
3647
+ const owner = currentRenderingInstance;
3648
+ if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
3649
+ // already pending
3650
+ factory.owners.push(owner);
3651
+ }
3652
+
3634
3653
  if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
3635
3654
  return factory.loadingComp
3636
3655
  }
3637
3656
 
3638
- const owner = currentRenderingInstance;
3639
- if (isDef(factory.owners)) {
3640
- // already pending
3641
- factory.owners.push(owner);
3642
- } else {
3657
+ if (owner && !isDef(factory.owners)) {
3643
3658
  const owners = factory.owners = [owner];
3644
3659
  let sync = true;
3660
+ let timerLoading = null;
3661
+ let timerTimeout = null
3662
+
3663
+ ;(owner).$on('hook:destroyed', () => remove(owners, owner));
3645
3664
 
3646
3665
  const forceRender = (renderCompleted) => {
3647
3666
  for (let i = 0, l = owners.length; i < l; i++) {
@@ -3650,6 +3669,14 @@ function resolveAsyncComponent (
3650
3669
 
3651
3670
  if (renderCompleted) {
3652
3671
  owners.length = 0;
3672
+ if (timerLoading !== null) {
3673
+ clearTimeout(timerLoading);
3674
+ timerLoading = null;
3675
+ }
3676
+ if (timerTimeout !== null) {
3677
+ clearTimeout(timerTimeout);
3678
+ timerTimeout = null;
3679
+ }
3653
3680
  }
3654
3681
  };
3655
3682
 
@@ -3696,7 +3723,8 @@ function resolveAsyncComponent (
3696
3723
  if (res.delay === 0) {
3697
3724
  factory.loading = true;
3698
3725
  } else {
3699
- setTimeout(() => {
3726
+ timerLoading = setTimeout(() => {
3727
+ timerLoading = null;
3700
3728
  if (isUndef(factory.resolved) && isUndef(factory.error)) {
3701
3729
  factory.loading = true;
3702
3730
  forceRender(false);
@@ -3706,7 +3734,8 @@ function resolveAsyncComponent (
3706
3734
  }
3707
3735
 
3708
3736
  if (isDef(res.timeout)) {
3709
- setTimeout(() => {
3737
+ timerTimeout = setTimeout(() => {
3738
+ timerTimeout = null;
3710
3739
  if (isUndef(factory.resolved)) {
3711
3740
  reject(
3712
3741
  `timeout (${res.timeout}ms)`
@@ -4252,11 +4281,21 @@ let getNow = Date.now;
4252
4281
  // timestamp can either be hi-res (relative to page load) or low-res
4253
4282
  // (relative to UNIX epoch), so in order to compare time we have to use the
4254
4283
  // same timestamp type when saving the flush timestamp.
4255
- if (inBrowser && getNow() > document.createEvent('Event').timeStamp) {
4256
- // if the low-res timestamp which is bigger than the event timestamp
4257
- // (which is evaluated AFTER) it means the event is using a hi-res timestamp,
4258
- // and we need to use the hi-res version for event listeners as well.
4259
- getNow = () => performance.now();
4284
+ // All IE versions use low-res event timestamps, and have problematic clock
4285
+ // implementations (#9632)
4286
+ if (inBrowser && !isIE) {
4287
+ const performance = window.performance;
4288
+ if (
4289
+ performance &&
4290
+ typeof performance.now === 'function' &&
4291
+ getNow() > document.createEvent('Event').timeStamp
4292
+ ) {
4293
+ // if the event timestamp, although evaluated AFTER the Date.now(), is
4294
+ // smaller than it, it means the event is using a hi-res timestamp,
4295
+ // and we need to use the hi-res version for event listener timestamps as
4296
+ // well.
4297
+ getNow = () => performance.now();
4298
+ }
4260
4299
  }
4261
4300
 
4262
4301
  /**
@@ -5431,7 +5470,7 @@ Object.defineProperty(Vue, 'FunctionalRenderContext', {
5431
5470
  value: FunctionalRenderContext
5432
5471
  });
5433
5472
 
5434
- Vue.version = '2.6.7';
5473
+ Vue.version = '2.6.11';
5435
5474
 
5436
5475
  /* */
5437
5476
 
@@ -6103,7 +6142,7 @@ function createPatchFunction (backend) {
6103
6142
  }
6104
6143
  }
6105
6144
 
6106
- function removeVnodes (parentElm, vnodes, startIdx, endIdx) {
6145
+ function removeVnodes (vnodes, startIdx, endIdx) {
6107
6146
  for (; startIdx <= endIdx; ++startIdx) {
6108
6147
  const ch = vnodes[startIdx];
6109
6148
  if (isDef(ch)) {
@@ -6214,7 +6253,7 @@ function createPatchFunction (backend) {
6214
6253
  refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
6215
6254
  addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
6216
6255
  } else if (newStartIdx > newEndIdx) {
6217
- removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
6256
+ removeVnodes(oldCh, oldStartIdx, oldEndIdx);
6218
6257
  }
6219
6258
  }
6220
6259
 
@@ -6306,7 +6345,7 @@ function createPatchFunction (backend) {
6306
6345
  if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '');
6307
6346
  addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
6308
6347
  } else if (isDef(oldCh)) {
6309
- removeVnodes(elm, oldCh, 0, oldCh.length - 1);
6348
+ removeVnodes(oldCh, 0, oldCh.length - 1);
6310
6349
  } else if (isDef(oldVnode.text)) {
6311
6350
  nodeOps.setTextContent(elm, '');
6312
6351
  }
@@ -6533,7 +6572,7 @@ function createPatchFunction (backend) {
6533
6572
 
6534
6573
  // destroy old node
6535
6574
  if (isDef(parentElm)) {
6536
- removeVnodes(parentElm, [oldVnode], 0, 0);
6575
+ removeVnodes([oldVnode], 0, 0);
6537
6576
  } else if (isDef(oldVnode.tag)) {
6538
6577
  invokeDestroyHook(oldVnode);
6539
6578
  }
@@ -7515,8 +7554,10 @@ function add$1 (
7515
7554
  e.target === e.currentTarget ||
7516
7555
  // event is fired after handler attachment
7517
7556
  e.timeStamp >= attachedTimestamp ||
7518
- // #9462 bail for iOS 9 bug: event.timeStamp is 0 after history.pushState
7519
- e.timeStamp === 0 ||
7557
+ // bail for environments that have buggy event.timeStamp implementations
7558
+ // #9462 iOS 9 bug: event.timeStamp is 0 after history.pushState
7559
+ // #9681 QtWebEngine event.timeStamp is negative value
7560
+ e.timeStamp <= 0 ||
7520
7561
  // #9448 bail if event is fired in another document in a multi-page
7521
7562
  // electron/nw.js app, since event.timeStamp will be using a different
7522
7563
  // starting reference
@@ -7583,10 +7624,11 @@ function updateDOMProps (oldVnode, vnode) {
7583
7624
  }
7584
7625
 
7585
7626
  for (key in oldProps) {
7586
- if (isUndef(props[key])) {
7627
+ if (!(key in props)) {
7587
7628
  elm[key] = '';
7588
7629
  }
7589
7630
  }
7631
+
7590
7632
  for (key in props) {
7591
7633
  cur = props[key];
7592
7634
  // ignore children if the node has textContent or innerHTML,
@@ -8133,8 +8175,8 @@ function enter (vnode, toggleDisplay) {
8133
8175
  let context = activeInstance;
8134
8176
  let transitionNode = activeInstance.$vnode;
8135
8177
  while (transitionNode && transitionNode.parent) {
8136
- transitionNode = transitionNode.parent;
8137
8178
  context = transitionNode.context;
8179
+ transitionNode = transitionNode.parent;
8138
8180
  }
8139
8181
 
8140
8182
  const isAppear = !context._isMounted || !vnode.isRootInsert;
@@ -9219,13 +9261,13 @@ const isNonPhrasingTag = makeMap(
9219
9261
  // Regular Expressions for parsing tags and attributes
9220
9262
  const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
9221
9263
  const dynamicArgAttribute = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
9222
- const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeLetters}]*`;
9264
+ const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeRegExp.source}]*`;
9223
9265
  const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
9224
9266
  const startTagOpen = new RegExp(`^<${qnameCapture}`);
9225
9267
  const startTagClose = /^\s*(\/?)>/;
9226
9268
  const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`);
9227
9269
  const doctype = /^<!DOCTYPE [^>]+>/i;
9228
- // #7298: escape - to avoid being pased as HTML comment when inlined in page
9270
+ // #7298: escape - to avoid being passed as HTML comment when inlined in page
9229
9271
  const comment = /^<!\--/;
9230
9272
  const conditionalComment = /^<!\[/;
9231
9273
 
@@ -9481,7 +9523,7 @@ function parseHTML (html, options) {
9481
9523
  ) {
9482
9524
  options.warn(
9483
9525
  `tag <${stack[i].tag}> has no matching end tag.`,
9484
- { start: stack[i].start }
9526
+ { start: stack[i].start, end: stack[i].end }
9485
9527
  );
9486
9528
  }
9487
9529
  if (options.end) {
@@ -9510,7 +9552,7 @@ function parseHTML (html, options) {
9510
9552
  /* */
9511
9553
 
9512
9554
  const onRE = /^@|^v-on:/;
9513
- const dirRE = /^v-|^@|^:/;
9555
+ const dirRE = /^v-|^@|^:|^#/;
9514
9556
  const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
9515
9557
  const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
9516
9558
  const stripParensRE = /^\(|\)$/g;
@@ -9518,7 +9560,7 @@ const dynamicArgRE = /^\[.*\]$/;
9518
9560
 
9519
9561
  const argRE = /:(.*)$/;
9520
9562
  const bindRE = /^:|^\.|^v-bind:/;
9521
- const modifierRE = /\.[^.]+/g;
9563
+ const modifierRE = /\.[^.\]]+(?=[^\]]*$)/g;
9522
9564
 
9523
9565
  const slotRE = /^v-slot(:|$)|^#/;
9524
9566
 
@@ -9695,7 +9737,7 @@ function parse (
9695
9737
  shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,
9696
9738
  shouldKeepComment: options.comments,
9697
9739
  outputSourceRange: options.outputSourceRange,
9698
- start (tag, attrs, unary, start) {
9740
+ start (tag, attrs, unary, start, end) {
9699
9741
  // check namespace.
9700
9742
  // inherit parent ns if there is one
9701
9743
  const ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag);
@@ -9714,6 +9756,7 @@ function parse (
9714
9756
  {
9715
9757
  if (options.outputSourceRange) {
9716
9758
  element.start = start;
9759
+ element.end = end;
9717
9760
  element.rawAttrsMap = element.attrsList.reduce((cumulated, attr) => {
9718
9761
  cumulated[attr.name] = attr;
9719
9762
  return cumulated
@@ -9835,7 +9878,7 @@ function parse (
9835
9878
  text = preserveWhitespace ? ' ' : '';
9836
9879
  }
9837
9880
  if (text) {
9838
- if (whitespaceOption === 'condense') {
9881
+ if (!inPre && whitespaceOption === 'condense') {
9839
9882
  // condense consecutive whitespaces into single space
9840
9883
  text = text.replace(whitespaceRE$1, ' ');
9841
9884
  }
@@ -10133,7 +10176,7 @@ function processSlotContent (el) {
10133
10176
  if (el.parent && !maybeComponent(el.parent)) {
10134
10177
  warn$2(
10135
10178
  `<template v-slot> can only appear at the root level inside ` +
10136
- `the receiving the component`,
10179
+ `the receiving component`,
10137
10180
  el
10138
10181
  );
10139
10182
  }
@@ -10692,7 +10735,7 @@ function isDirectChildOfTemplateFor (node) {
10692
10735
 
10693
10736
  /* */
10694
10737
 
10695
- const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/;
10738
+ const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/;
10696
10739
  const fnInvokeRE = /\([^)]*?\);*$/;
10697
10740
  const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/;
10698
10741
 
@@ -11240,7 +11283,7 @@ function genScopedSlots (
11240
11283
  // components with only scoped slots to skip forced updates from parent.
11241
11284
  // but in some cases we have to bail-out of this optimization
11242
11285
  // for example if the slot contains dynamic names, has v-if or v-for on them...
11243
- let needsForceUpdate = Object.keys(slots).some(key => {
11286
+ let needsForceUpdate = el.for || Object.keys(slots).some(key => {
11244
11287
  const slot = slots[key];
11245
11288
  return (
11246
11289
  slot.slotTargetDynamic ||
@@ -11517,6 +11560,8 @@ function checkNode (node, warn) {
11517
11560
  const range = node.rawAttrsMap[name];
11518
11561
  if (name === 'v-for') {
11519
11562
  checkFor(node, `v-for="${value}"`, warn, range);
11563
+ } else if (name === 'v-slot' || name[0] === '#') {
11564
+ checkFunctionParameterExpression(value, `${name}="${value}"`, warn, range);
11520
11565
  } else if (onRE.test(name)) {
11521
11566
  checkEvent(value, `${name}="${value}"`, warn, range);
11522
11567
  } else {
@@ -11536,9 +11581,9 @@ function checkNode (node, warn) {
11536
11581
  }
11537
11582
 
11538
11583
  function checkEvent (exp, text, warn, range) {
11539
- const stipped = exp.replace(stripStringRE, '');
11540
- const keywordMatch = stipped.match(unaryOperatorsRE);
11541
- if (keywordMatch && stipped.charAt(keywordMatch.index - 1) !== '$') {
11584
+ const stripped = exp.replace(stripStringRE, '');
11585
+ const keywordMatch = stripped.match(unaryOperatorsRE);
11586
+ if (keywordMatch && stripped.charAt(keywordMatch.index - 1) !== '$') {
11542
11587
  warn(
11543
11588
  `avoid using JavaScript unary operator as property name: ` +
11544
11589
  `"${keywordMatch[0]}" in expression ${text.trim()}`,
@@ -11593,6 +11638,19 @@ function checkExpression (exp, text, warn, range) {
11593
11638
  }
11594
11639
  }
11595
11640
 
11641
+ function checkFunctionParameterExpression (exp, text, warn, range) {
11642
+ try {
11643
+ new Function(exp, '');
11644
+ } catch (e) {
11645
+ warn(
11646
+ `invalid function parameter expression: ${e.message} in\n\n` +
11647
+ ` ${exp}\n\n` +
11648
+ ` Raw expression: ${text.trim()}\n`,
11649
+ range
11650
+ );
11651
+ }
11652
+ }
11653
+
11596
11654
  /* */
11597
11655
 
11598
11656
  const range = 2;