From 0101fb08e93d0bbe58683003bfcbf78de3515b4b Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Fri, 23 Oct 2020 14:47:24 +0800 Subject: [PATCH] build: 3.0.2 --- packages/uni-h5-vue/dist/vue.runtime.esm.js | 2891 +++++++++-------- packages/uni-h5-vue/lib/vue.runtime.esm.js | 2891 +++++++++-------- packages/uni-h5/dist/uni-h5.esm.js | 210 +- packages/uni-mp-alipay/dist/uni.api.esm.js | 17 +- packages/uni-mp-baidu/dist/uni.api.esm.js | 17 +- packages/uni-mp-qq/dist/uni.api.esm.js | 17 +- packages/uni-mp-toutiao/dist/uni.api.esm.js | 17 +- packages/uni-mp-vue/dist/vue.runtime.esm.js | 217 +- packages/uni-mp-vue/lib/vue.runtime.esm.js | 217 +- packages/uni-mp-weixin/dist/uni.api.esm.js | 17 +- .../uni-quickapp-webview/dist/uni.api.esm.js | 17 +- 11 files changed, 3580 insertions(+), 2948 deletions(-) diff --git a/packages/uni-h5-vue/dist/vue.runtime.esm.js b/packages/uni-h5-vue/dist/vue.runtime.esm.js index e9f493eec..f7842e3e4 100644 --- a/packages/uni-h5-vue/dist/vue.runtime.esm.js +++ b/packages/uni-h5-vue/dist/vue.runtime.esm.js @@ -1,5 +1,5 @@ -import { isSymbol, extend, isMap, isObject, toRawType, def, isArray, isString, isFunction, isPromise, capitalize, EMPTY_ARR, normalizeClass, normalizeStyle, isOn, remove, EMPTY_OBJ, NOOP, isGloballyWhitelisted, toNumber, invokeArrayFns, looseIndexOf, isSet, looseHas, looseEqual, hyphenate, isHTMLTag, isSVGTag, isIntegerKey, hasOwn, hasChanged, camelize, getGlobalThis, isReservedProp, NO, isModelListener, makeMap, isSpecialBooleanAttr } from '@vue/shared'; -export { camelize, capitalize, toDisplayString } from '@vue/shared'; +import { isSymbol, extend, isMap, isObject, toRawType, def, isArray, isString, isFunction, isPromise, toHandlerKey, remove, EMPTY_OBJ, camelize, capitalize, EMPTY_ARR, normalizeClass, normalizeStyle, isOn, NOOP, isGloballyWhitelisted, toNumber, invokeArrayFns, looseIndexOf, isSet, looseEqual, hyphenate, isHTMLTag, isSVGTag, isIntegerKey, hasOwn, hasChanged, getGlobalThis, isReservedProp, NO, isModelListener, makeMap, isSpecialBooleanAttr } from '@vue/shared'; +export { camelize, capitalize, toDisplayString, toHandlerKey } from '@vue/shared'; const targetMap = new WeakMap(); const effectStack = []; @@ -50,6 +50,7 @@ function createReactiveEffect(fn, options) { } }; effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; effect._isEffect = true; effect.active = true; effect.raw = fn; @@ -115,7 +116,7 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) { const add = (effectsToAdd) => { if (effectsToAdd) { effectsToAdd.forEach(effect => { - if (effect !== activeEffect || effect.options.allowRecurse) { + if (effect !== activeEffect || effect.allowRecurse) { effects.add(effect); } }); @@ -220,7 +221,7 @@ const arrayInstrumentations = {}; arrayInstrumentations[key] = function (...args) { pauseTracking(); const res = method.apply(this, args); - enableTracking(); + resetTracking(); return res; }; }); @@ -241,8 +242,7 @@ function createGetter(isReadonly = false, shallow = false) { return Reflect.get(arrayInstrumentations, key, receiver); } const res = Reflect.get(target, key, receiver); - const keyIsSymbol = isSymbol(key); - if (keyIsSymbol + if (isSymbol(key) ? builtInSymbols.has(key) : key === `__proto__` || key === `__v_isRef`) { return res; @@ -312,7 +312,7 @@ function has(target, key) { return result; } function ownKeys(target) { - track(target, "iterate" /* ITERATE */, ITERATE_KEY); + track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY); return Reflect.ownKeys(target); } const mutableHandlers = { @@ -595,7 +595,7 @@ function checkIdentityKeys(target, has, key) { if (rawKey !== key && has.call(target, rawKey)) { const type = toRawType(target); console.warn(`Reactive ${type} contains both the raw and reactive ` + - `versions of the same object${type === `Map` ? `as keys` : ``}, ` + + `versions of the same object${type === `Map` ? ` as keys` : ``}, ` + `which can lead to inconsistencies. ` + `Avoid differentiating between the raw and reactive versions ` + `of an object and only use the reactive version if possible.`); @@ -730,7 +730,7 @@ function createRef(rawValue, shallow = false) { return new RefImpl(rawValue, shallow); } function triggerRef(ref) { - trigger(ref, "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); + trigger(toRaw(ref), "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); } function unref(ref) { return isRef(ref) ? ref.value : ref; @@ -1028,7 +1028,7 @@ function handleError(err, instance, type, throwInDev = true) { const errorCapturedHooks = cur.ec; if (errorCapturedHooks) { for (let i = 0; i < errorCapturedHooks.length; i++) { - if (errorCapturedHooks[i](err, exposedInstance, errorInfo)) { + if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) { return; } } @@ -1084,7 +1084,7 @@ let currentPreFlushParentJob = null; const RECURSION_LIMIT = 100; function nextTick(fn) { const p = currentFlushPromise || resolvedPromise; - return fn ? p.then(fn) : p; + return fn ? p.then(this ? fn.bind(this) : fn) : p; } function queueJob(job) { // the dedupe search uses the startIndex argument of Array.includes() @@ -1247,7 +1247,7 @@ const hmrDirtyComponents = new Set(); // it easier to be used in toolings like vue-loader // Note: for a component to be eligible for HMR it also needs the __hmrId option // to be set so that its instances can be registered / removed. -if ((process.env.NODE_ENV !== 'production')) { +if ((process.env.NODE_ENV !== 'production') && (true )) { const globalObject = typeof global !== 'undefined' ? global : typeof self !== 'undefined' @@ -1391,21 +1391,21 @@ function devtoolsComponentEmit(component, event, params) { devtools.emit("component:emit" /* COMPONENT_EMIT */, component.appContext.app, component, event, params); } -function emit(instance, event, ...args) { +function emit(instance, event, ...rawArgs) { const props = instance.vnode.props || EMPTY_OBJ; if ((process.env.NODE_ENV !== 'production')) { const { emitsOptions, propsOptions: [propsOptions] } = instance; if (emitsOptions) { if (!(event in emitsOptions)) { - if (!propsOptions || !(`on` + capitalize(event) in propsOptions)) { + if (!propsOptions || !(toHandlerKey(event) in propsOptions)) { warn(`Component emitted event "${event}" but it is neither declared in ` + - `the emits option nor as an "on${capitalize(event)}" prop.`); + `the emits option nor as an "${toHandlerKey(event)}" prop.`); } } else { const validator = emitsOptions[event]; if (isFunction(validator)) { - const isValid = validator(...args); + const isValid = validator(...rawArgs); if (!isValid) { warn(`Invalid event arguments: event validation failed for event "${event}".`); } @@ -1413,36 +1413,59 @@ function emit(instance, event, ...args) { } } } + let args = rawArgs; + const isModelListener = event.startsWith('update:'); + // for v-model update:xxx events, apply modifiers on args + const modelArg = isModelListener && event.slice(7); + if (modelArg && modelArg in props) { + const modifiersKey = `${modelArg === 'modelValue' ? 'model' : modelArg}Modifiers`; + const { number, trim } = props[modifiersKey] || EMPTY_OBJ; + if (trim) { + args = rawArgs.map(a => a.trim()); + } + else if (number) { + args = rawArgs.map(toNumber); + } + } if ((process.env.NODE_ENV !== 'production') || __VUE_PROD_DEVTOOLS__) { devtoolsComponentEmit(instance, event, args); } - let handlerName = `on${capitalize(event)}`; + if ((process.env.NODE_ENV !== 'production')) { + const lowerCaseEvent = event.toLowerCase(); + if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) { + warn(`Event "${lowerCaseEvent}" is emitted in component ` + + `${formatComponentName(instance, instance.type)} but the handler is registered for "${event}". ` + + `Note that HTML attributes are case-insensitive and you cannot use ` + + `v-on to listen to camelCase events when using in-DOM templates. ` + + `You should probably use "${hyphenate(event)}" instead of "${event}".`); + } + } + // convert handler name to camelCase. See issue #2249 + let handlerName = toHandlerKey(camelize(event)); let handler = props[handlerName]; // for v-model update:xxx events, also trigger kebab-case equivalent // for props passed via kebab-case - if (!handler && event.startsWith('update:')) { - handlerName = `on${capitalize(hyphenate(event))}`; + if (!handler && isModelListener) { + handlerName = toHandlerKey(hyphenate(event)); handler = props[handlerName]; } - if (!handler) { - handler = props[handlerName + `Once`]; + if (handler) { + callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); + } + const onceHandler = props[handlerName + `Once`]; + if (onceHandler) { if (!instance.emitted) { (instance.emitted = {})[handlerName] = true; } else if (instance.emitted[handlerName]) { return; } - } - if (handler) { - callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); + callWithAsyncErrorHandling(onceHandler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { - const appId = appContext.app ? appContext.app._uid : -1; - const cache = comp.__emits || (comp.__emits = {}); - const cached = cache[appId]; - if (cached !== undefined) { - return cached; + if (!appContext.deopt && comp.__emits !== undefined) { + return comp.__emits; } const raw = comp.emits; let normalized = {}; @@ -1464,7 +1487,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (cache[appId] = null); + return (comp.__emits = null); } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -1472,7 +1495,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { else { extend(normalized, raw); } - return (cache[appId] = normalized); + return (comp.__emits = normalized); } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are @@ -1603,7 +1626,7 @@ function renderComponentRoot(instance) { warn(`Runtime directive used on component with non-element root node. ` + `The directives will not function as intended.`); } - root.dirs = vnode.dirs; + root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs; } // inherit transition data if (vnode.transition) { @@ -1647,11 +1670,13 @@ const getChildRoot = (vnode) => { const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1; const setRoot = (updatedRoot) => { rawChildren[index] = updatedRoot; - if (dynamicIndex > -1) { - dynamicChildren[dynamicIndex] = updatedRoot; - } - else if (dynamicChildren && updatedRoot.patchFlag > 0) { - dynamicChildren.push(updatedRoot); + if (dynamicChildren) { + if (dynamicIndex > -1) { + dynamicChildren[dynamicIndex] = updatedRoot; + } + else if (updatedRoot.patchFlag > 0) { + vnode.dynamicChildren = [...dynamicChildren, updatedRoot]; + } } }; return [normalizeVNode(childRoot), setRoot]; @@ -1789,7 +1814,7 @@ const SuspenseImpl = { mountSuspense(n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, rendererInternals); } else { - patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimized, rendererInternals); + patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, rendererInternals); } }, hydrate: hydrateSuspense, @@ -1803,13 +1828,13 @@ function mountSuspense(vnode, container, anchor, parentComponent, parentSuspense const hiddenContainer = createElement('div'); const suspense = (vnode.suspense = createSuspenseBoundary(vnode, parentSuspense, parentComponent, container, hiddenContainer, anchor, isSVG, optimized, rendererInternals)); // start mounting the content subtree in an off-dom container - patch(null, (suspense.pendingBranch = vnode.ssContent), hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(null, (suspense.pendingBranch = vnode.ssContent), hiddenContainer, null, parentComponent, suspense, isSVG); // now check if we have encountered any async deps if (suspense.deps > 0) { // has async // mount the fallback tree patch(null, vnode.ssFallback, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); + isSVG); setActiveBranch(suspense, vnode.ssFallback); } else { @@ -1817,7 +1842,7 @@ function mountSuspense(vnode, container, anchor, parentComponent, parentSuspense suspense.resolve(); } } -function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimized, { p: patch, um: unmount, o: { createElement } }) { +function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, { p: patch, um: unmount, o: { createElement } }) { const suspense = (n2.suspense = n1.suspense); suspense.vnode = n2; n2.el = n1.el; @@ -1828,13 +1853,13 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimi suspense.pendingBranch = newBranch; if (isSameVNodeType(newBranch, pendingBranch)) { // same root type but content may have changed. - patch(pendingBranch, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(pendingBranch, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG); if (suspense.deps <= 0) { suspense.resolve(); } else if (isInFallback) { patch(activeBranch, newFallback, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); + isSVG); setActiveBranch(suspense, newFallback); } } @@ -1860,25 +1885,25 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimi suspense.hiddenContainer = createElement('div'); if (isInFallback) { // already in fallback state - patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG); if (suspense.deps <= 0) { suspense.resolve(); } else { patch(activeBranch, newFallback, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); + isSVG); setActiveBranch(suspense, newFallback); } } else if (activeBranch && isSameVNodeType(newBranch, activeBranch)) { // toggled "back" to current active branch - patch(activeBranch, newBranch, container, anchor, parentComponent, suspense, isSVG, optimized); + patch(activeBranch, newBranch, container, anchor, parentComponent, suspense, isSVG); // force resolve suspense.resolve(true); } else { // switched to a 3rd branch - patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG); if (suspense.deps <= 0) { suspense.resolve(); } @@ -1888,7 +1913,7 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimi else { if (activeBranch && isSameVNodeType(newBranch, activeBranch)) { // root did not change, just normal patch - patch(activeBranch, newBranch, container, anchor, parentComponent, suspense, isSVG, optimized); + patch(activeBranch, newBranch, container, anchor, parentComponent, suspense, isSVG); setActiveBranch(suspense, newBranch); } else { @@ -1901,7 +1926,7 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimi // mount pending branch in off-dom container suspense.pendingBranch = newBranch; suspense.pendingId++; - patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG); if (suspense.deps <= 0) { // incoming branch has no async deps, resolve now. suspense.resolve(); @@ -1937,7 +1962,6 @@ function createSuspenseBoundary(vnode, parent, parentComponent, container, hidde parent, parentComponent, isSVG, - optimized, container, hiddenContainer, anchor, @@ -2020,7 +2044,7 @@ function createSuspenseBoundary(vnode, parent, parentComponent, container, hidde if (!suspense.pendingBranch) { return; } - const { vnode, activeBranch, parentComponent, container, isSVG, optimized } = suspense; + const { vnode, activeBranch, parentComponent, container, isSVG } = suspense; // invoke @fallback event const onFallback = vnode.props && vnode.props.onFallback; if (isFunction(onFallback)) { @@ -2033,7 +2057,7 @@ function createSuspenseBoundary(vnode, parent, parentComponent, container, hidde } // mount the fallback tree patch(null, fallbackVNode, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); + isSVG); setActiveBranch(suspense, fallbackVNode); }; const delayEnter = fallbackVNode.transition && fallbackVNode.transition.mode === 'out-in'; @@ -2277,1128 +2301,655 @@ function withScopeId(id) { })); } -const isTeleport = (type) => type.__isTeleport; -const isTeleportDisabled = (props) => props && (props.disabled || props.disabled === ''); -const resolveTarget = (props, select) => { - const targetSelector = props && props.to; - if (isString(targetSelector)) { - if (!select) { - (process.env.NODE_ENV !== 'production') && - warn(`Current renderer does not support string target for Teleports. ` + - `(missing querySelector renderer option)`); - return null; - } - else { - const target = select(targetSelector); - if (!target) { - (process.env.NODE_ENV !== 'production') && - warn(`Failed to locate Teleport target with selector "${targetSelector}". ` + - `Note the target element must exist before the component is mounted - ` + - `i.e. the target cannot be rendered by the component itself, and ` + - `ideally should be outside of the entire Vue component tree.`); - } - return target; - } +function initProps(instance, rawProps, isStateful, // result of bitwise flag comparison +isSSR = false) { + const props = {}; + const attrs = {}; + def(attrs, InternalObjectKey, 1); + setFullProps(instance, rawProps, props, attrs); + // validation + if ((process.env.NODE_ENV !== 'production')) { + validateProps(props, instance); } - else { - if ((process.env.NODE_ENV !== 'production') && !targetSelector && !isTeleportDisabled(props)) { - warn(`Invalid Teleport target: ${targetSelector}`); - } - return targetSelector; + if (isStateful) { + // stateful + instance.props = isSSR ? props : shallowReactive(props); } -}; -const TeleportImpl = { - __isTeleport: true, - process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals) { - const { mc: mountChildren, pc: patchChildren, pbc: patchBlockChildren, o: { insert, querySelector, createText, createComment } } = internals; - const disabled = isTeleportDisabled(n2.props); - const { shapeFlag, children } = n2; - if (n1 == null) { - // insert anchors in the main view - const placeholder = (n2.el = (process.env.NODE_ENV !== 'production') - ? createComment('teleport start') - : createText('')); - const mainAnchor = (n2.anchor = (process.env.NODE_ENV !== 'production') - ? createComment('teleport end') - : createText('')); - insert(placeholder, container, anchor); - insert(mainAnchor, container, anchor); - const target = (n2.target = resolveTarget(n2.props, querySelector)); - const targetAnchor = (n2.targetAnchor = createText('')); - if (target) { - insert(targetAnchor, target); - } - else if ((process.env.NODE_ENV !== 'production') && !disabled) { - warn('Invalid Teleport target on mount:', target, `(${typeof target})`); - } - const mount = (container, anchor) => { - // Teleport *always* has Array children. This is enforced in both the - // compiler and vnode children normalization. - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - mountChildren(children, container, anchor, parentComponent, parentSuspense, isSVG, optimized); - } - }; - if (disabled) { - mount(container, mainAnchor); - } - else if (target) { - mount(target, targetAnchor); - } + else { + if (!instance.type.props) { + // functional w/ optional props, props === attrs + instance.props = attrs; } else { - // update content - n2.el = n1.el; - const mainAnchor = (n2.anchor = n1.anchor); - const target = (n2.target = n1.target); - const targetAnchor = (n2.targetAnchor = n1.targetAnchor); - const wasDisabled = isTeleportDisabled(n1.props); - const currentContainer = wasDisabled ? container : target; - const currentAnchor = wasDisabled ? mainAnchor : targetAnchor; - if (n2.dynamicChildren) { - // fast path when the teleport happens to be a block root - patchBlockChildren(n1.dynamicChildren, n2.dynamicChildren, currentContainer, parentComponent, parentSuspense, isSVG); - // even in block tree mode we need to make sure all root-level nodes - // in the teleport inherit previous DOM references so that they can - // be moved in future patches. - if (n2.shapeFlag & 16 /* ARRAY_CHILDREN */) { - const oldChildren = n1.children; - const children = n2.children; - for (let i = 0; i < children.length; i++) { - // only inherit for non-patched nodes (i.e. static ones) - if (!children[i].el) { - children[i].el = oldChildren[i].el; - } + // functional w/ declared props + instance.props = props; + } + } + instance.attrs = attrs; +} +function updateProps(instance, rawProps, rawPrevProps, optimized) { + const { props, attrs, vnode: { patchFlag } } = instance; + const rawCurrentProps = toRaw(props); + const [options] = instance.propsOptions; + if ( + // always force full diff in dev + // - #1942 if hmr is enabled with sfc component + // - vite#872 non-sfc component used by sfc component + !((process.env.NODE_ENV !== 'production') && + (instance.type.__hmrId || + (instance.parent && instance.parent.type.__hmrId))) && + (optimized || patchFlag > 0) && + !(patchFlag & 16 /* FULL_PROPS */)) { + if (patchFlag & 8 /* PROPS */) { + // Compiler-generated props & no keys change, just set the updated + // the props. + const propsToUpdate = instance.vnode.dynamicProps; + for (let i = 0; i < propsToUpdate.length; i++) { + const key = propsToUpdate[i]; + // PROPS flag guarantees rawProps to be non-null + const value = rawProps[key]; + if (options) { + // attr / props separation was done on init and will be consistent + // in this code path, so just check if attrs have it. + if (hasOwn(attrs, key)) { + attrs[key] = value; + } + else { + const camelizedKey = camelize(key); + props[camelizedKey] = resolvePropValue(options, rawCurrentProps, camelizedKey, value, instance); } } - } - else if (!optimized) { - patchChildren(n1, n2, currentContainer, currentAnchor, parentComponent, parentSuspense, isSVG); - } - if (disabled) { - if (!wasDisabled) { - // enabled -> disabled - // move into main container - moveTeleport(n2, container, mainAnchor, internals, 1 /* TOGGLE */); + else { + attrs[key] = value; } } - else { - // target changed - if ((n2.props && n2.props.to) !== (n1.props && n1.props.to)) { - const nextTarget = (n2.target = resolveTarget(n2.props, querySelector)); - if (nextTarget) { - moveTeleport(n2, nextTarget, null, internals, 0 /* TARGET_CHANGE */); - } - else if ((process.env.NODE_ENV !== 'production')) { - warn('Invalid Teleport target on update:', target, `(${typeof target})`); + } + } + else { + // full props update. + setFullProps(instance, rawProps, props, attrs); + // in case of dynamic props, check if we need to delete keys from + // the props object + let kebabKey; + for (const key in rawCurrentProps) { + if (!rawProps || + // for camelCase + (!hasOwn(rawProps, key) && + // it's possible the original props was passed in as kebab-case + // and converted to camelCase (#955) + ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey)))) { + if (options) { + if (rawPrevProps && + // for camelCase + (rawPrevProps[key] !== undefined || + // for kebab-case + rawPrevProps[kebabKey] !== undefined)) { + props[key] = resolvePropValue(options, rawProps || EMPTY_OBJ, key, undefined, instance); } } - else if (wasDisabled) { - // disabled -> enabled - // move into teleport target - moveTeleport(n2, target, targetAnchor, internals, 1 /* TOGGLE */); + else { + delete props[key]; } } } - }, - remove(vnode, { r: remove, o: { remove: hostRemove } }) { - const { shapeFlag, children, anchor } = vnode; - hostRemove(anchor); - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - for (let i = 0; i < children.length; i++) { - remove(children[i]); + // in the case of functional component w/o props declaration, props and + // attrs point to the same object so it should already have been updated. + if (attrs !== rawCurrentProps) { + for (const key in attrs) { + if (!rawProps || !hasOwn(rawProps, key)) { + delete attrs[key]; + } } } - }, - move: moveTeleport, - hydrate: hydrateTeleport -}; -function moveTeleport(vnode, container, parentAnchor, { o: { insert }, m: move }, moveType = 2 /* REORDER */) { - // move target anchor if this is a target change. - if (moveType === 0 /* TARGET_CHANGE */) { - insert(vnode.targetAnchor, container, parentAnchor); } - const { el, anchor, shapeFlag, children, props } = vnode; - const isReorder = moveType === 2 /* REORDER */; - // move main view anchor if this is a re-order. - if (isReorder) { - insert(el, container, parentAnchor); + // trigger updates for $attrs in case it's used in component slots + trigger(instance, "set" /* SET */, '$attrs'); + if ((process.env.NODE_ENV !== 'production') && rawProps) { + validateProps(props, instance); } - // if this is a re-order and teleport is enabled (content is in target) - // do not move children. So the opposite is: only move children if this - // is not a reorder, or the teleport is disabled - if (!isReorder || isTeleportDisabled(props)) { - // Teleport has either Array children or no children. - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - for (let i = 0; i < children.length; i++) { - move(children[i], container, parentAnchor, 2 /* REORDER */); +} +function setFullProps(instance, rawProps, props, attrs) { + const [options, needCastKeys] = instance.propsOptions; + if (rawProps) { + for (const key in rawProps) { + const value = rawProps[key]; + // key, ref are reserved and never passed down + if (isReservedProp(key)) { + continue; + } + // prop option names are camelized during normalization, so to support + // kebab -> camel conversion here we need to camelize the key. + let camelKey; + if (options && hasOwn(options, (camelKey = camelize(key)))) { + props[camelKey] = value; + } + else if (!isEmitListener(instance.emitsOptions, key)) { + // Any non-declared (either as a prop or an emitted event) props are put + // into a separate `attrs` object for spreading. Make sure to preserve + // original key casing + attrs[key] = value; } } } - // move main view anchor if this is a re-order. - if (isReorder) { - insert(anchor, container, parentAnchor); + if (needCastKeys) { + const rawCurrentProps = toRaw(props); + for (let i = 0; i < needCastKeys.length; i++) { + const key = needCastKeys[i]; + props[key] = resolvePropValue(options, rawCurrentProps, key, rawCurrentProps[key], instance); + } } } -function hydrateTeleport(node, vnode, parentComponent, parentSuspense, optimized, { o: { nextSibling, parentNode, querySelector } }, hydrateChildren) { - const target = (vnode.target = resolveTarget(vnode.props, querySelector)); - if (target) { - // if multiple teleports rendered to the same target element, we need to - // pick up from where the last teleport finished instead of the first node - const targetNode = target._lpa || target.firstChild; - if (vnode.shapeFlag & 16 /* ARRAY_CHILDREN */) { - if (isTeleportDisabled(vnode.props)) { - vnode.anchor = hydrateChildren(nextSibling(node), vnode, parentNode(node), parentComponent, parentSuspense, optimized); - vnode.targetAnchor = targetNode; +function resolvePropValue(options, props, key, value, instance) { + const opt = options[key]; + if (opt != null) { + const hasDefault = hasOwn(opt, 'default'); + // default values + if (hasDefault && value === undefined) { + const defaultValue = opt.default; + if (opt.type !== Function && isFunction(defaultValue)) { + setCurrentInstance(instance); + value = defaultValue(props); + setCurrentInstance(null); } else { - vnode.anchor = nextSibling(node); - vnode.targetAnchor = hydrateChildren(targetNode, vnode, target, parentComponent, parentSuspense, optimized); + value = defaultValue; + } + } + // boolean casting + if (opt[0 /* shouldCast */]) { + if (!hasOwn(props, key) && !hasDefault) { + value = false; + } + else if (opt[1 /* shouldCastTrue */] && + (value === '' || value === hyphenate(key))) { + value = true; } - target._lpa = - vnode.targetAnchor && nextSibling(vnode.targetAnchor); } } - return vnode.anchor && nextSibling(vnode.anchor); -} -// Force-casted public typing for h and TSX props inference -const Teleport = TeleportImpl; - -const COMPONENTS = 'components'; -const DIRECTIVES = 'directives'; -/** - * @private - */ -function resolveComponent(name) { - return resolveAsset(COMPONENTS, name) || name; + return value; } -const NULL_DYNAMIC_COMPONENT = Symbol(); -/** - * @private - */ -function resolveDynamicComponent(component) { - if (isString(component)) { - return resolveAsset(COMPONENTS, component, false) || component; +function normalizePropsOptions(comp, appContext, asMixin = false) { + if (!appContext.deopt && comp.__props) { + return comp.__props; } - else { - // invalid types will fallthrough to createVNode and raise warning - return (component || NULL_DYNAMIC_COMPONENT); + const raw = comp.props; + const normalized = {}; + const needCastKeys = []; + // apply mixin/extends props + let hasExtends = false; + if (__VUE_OPTIONS_API__ && !isFunction(comp)) { + const extendProps = (raw) => { + hasExtends = true; + const [props, keys] = normalizePropsOptions(raw, appContext, true); + extend(normalized, props); + if (keys) + needCastKeys.push(...keys); + }; + if (!asMixin && appContext.mixins.length) { + appContext.mixins.forEach(extendProps); + } + if (comp.extends) { + extendProps(comp.extends); + } + if (comp.mixins) { + comp.mixins.forEach(extendProps); + } } -} -/** - * @private - */ -function resolveDirective(name) { - return resolveAsset(DIRECTIVES, name); -} -// implementation -function resolveAsset(type, name, warnMissing = true) { - const instance = currentRenderingInstance || currentInstance; - if (instance) { - const Component = instance.type; - // self name has highest priority - if (type === COMPONENTS) { - const selfName = Component.displayName || Component.name; - if (selfName && - (selfName === name || - selfName === camelize(name) || - selfName === capitalize(camelize(name)))) { - return Component; + if (!raw && !hasExtends) { + return (comp.__props = EMPTY_ARR); + } + if (isArray(raw)) { + for (let i = 0; i < raw.length; i++) { + if ((process.env.NODE_ENV !== 'production') && !isString(raw[i])) { + warn(`props must be strings when using array syntax.`, raw[i]); + } + const normalizedKey = camelize(raw[i]); + if (validatePropName(normalizedKey)) { + normalized[normalizedKey] = EMPTY_OBJ; } } - const res = - // local registration - // check instance[type] first for components with mixin or extends. - resolve(instance[type] || Component[type], name) || - // global registration - resolve(instance.appContext[type], name); - if ((process.env.NODE_ENV !== 'production') && warnMissing && !res) { - warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + } + else if (raw) { + if ((process.env.NODE_ENV !== 'production') && !isObject(raw)) { + warn(`invalid props options`, raw); } - return res; + for (const key in raw) { + const normalizedKey = camelize(key); + if (validatePropName(normalizedKey)) { + const opt = raw[key]; + const prop = (normalized[normalizedKey] = + isArray(opt) || isFunction(opt) ? { type: opt } : opt); + if (prop) { + const booleanIndex = getTypeIndex(Boolean, prop.type); + const stringIndex = getTypeIndex(String, prop.type); + prop[0 /* shouldCast */] = booleanIndex > -1; + prop[1 /* shouldCastTrue */] = + stringIndex < 0 || booleanIndex < stringIndex; + // if the prop needs boolean casting or default value + if (booleanIndex > -1 || hasOwn(prop, 'default')) { + needCastKeys.push(normalizedKey); + } + } + } + } + } + return (comp.__props = [normalized, needCastKeys]); +} +function validatePropName(key) { + if (key[0] !== '$') { + return true; } else if ((process.env.NODE_ENV !== 'production')) { - warn(`resolve${capitalize(type.slice(0, -1))} ` + - `can only be used in render() or setup().`); + warn(`Invalid prop name: "${key}" is a reserved property.`); } + return false; } -function resolve(registry, name) { - return (registry && - (registry[name] || - registry[camelize(name)] || - registry[capitalize(camelize(name))])); -} - -const Fragment = Symbol((process.env.NODE_ENV !== 'production') ? 'Fragment' : undefined); -const Text = Symbol((process.env.NODE_ENV !== 'production') ? 'Text' : undefined); -const Comment = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : undefined); -const Static = Symbol((process.env.NODE_ENV !== 'production') ? 'Static' : undefined); -// Since v-if and v-for are the two possible ways node structure can dynamically -// change, once we consider v-if branches and each v-for fragment a block, we -// can divide a template into nested blocks, and within each block the node -// structure would be stable. This allows us to skip most children diffing -// and only worry about the dynamic nodes (indicated by patch flags). -const blockStack = []; -let currentBlock = null; -/** - * Open a block. - * This must be called before `createBlock`. It cannot be part of `createBlock` - * because the children of the block are evaluated before `createBlock` itself - * is called. The generated code typically looks like this: - * - * ```js - * function render() { - * return (openBlock(),createBlock('div', null, [...])) - * } - * ``` - * disableTracking is true when creating a v-for fragment block, since a v-for - * fragment always diffs its children. - * - * @private - */ -function openBlock(disableTracking = false) { - blockStack.push((currentBlock = disableTracking ? null : [])); +// use function string name to check type constructors +// so that it works across vms / iframes. +function getType(ctor) { + const match = ctor && ctor.toString().match(/^\s*function (\w+)/); + return match ? match[1] : ''; } -function closeBlock() { - blockStack.pop(); - currentBlock = blockStack[blockStack.length - 1] || null; +function isSameType(a, b) { + return getType(a) === getType(b); +} +function getTypeIndex(type, expectedTypes) { + if (isArray(expectedTypes)) { + for (let i = 0, len = expectedTypes.length; i < len; i++) { + if (isSameType(expectedTypes[i], type)) { + return i; + } + } + } + else if (isFunction(expectedTypes)) { + return isSameType(expectedTypes, type) ? 0 : -1; + } + return -1; } -// Whether we should be tracking dynamic child nodes inside a block. -// Only tracks when this value is > 0 -// We are not using a simple boolean because this value may need to be -// incremented/decremented by nested usage of v-once (see below) -let shouldTrack$1 = 1; /** - * Block tracking sometimes needs to be disabled, for example during the - * creation of a tree that needs to be cached by v-once. The compiler generates - * code like this: - * - * ``` js - * _cache[1] || ( - * setBlockTracking(-1), - * _cache[1] = createVNode(...), - * setBlockTracking(1), - * _cache[1] - * ) - * ``` - * - * @private + * dev only */ -function setBlockTracking(value) { - shouldTrack$1 += value; +function validateProps(props, instance) { + const rawValues = toRaw(props); + const options = instance.propsOptions[0]; + for (const key in options) { + let opt = options[key]; + if (opt == null) + continue; + validateProp(key, rawValues[key], opt, !hasOwn(rawValues, key)); + } } /** - * Create a block root vnode. Takes the same exact arguments as `createVNode`. - * A block root keeps track of dynamic nodes within the block in the - * `dynamicChildren` array. - * - * @private + * dev only */ -function createBlock(type, props, children, patchFlag, dynamicProps) { - const vnode = createVNode(type, props, children, patchFlag, dynamicProps, true /* isBlock: prevent a block from tracking itself */); - // save current block children on the block vnode - vnode.dynamicChildren = currentBlock || EMPTY_ARR; - // close block - closeBlock(); - // a block is always going to be patched, so track it as a child of its - // parent block - if (shouldTrack$1 > 0 && currentBlock) { - currentBlock.push(vnode); +function validateProp(name, value, prop, isAbsent) { + const { type, required, validator } = prop; + // required! + if (required && isAbsent) { + warn('Missing required prop: "' + name + '"'); + return; } - return vnode; -} -function isVNode(value) { - return value ? value.__v_isVNode === true : false; -} -function isSameVNodeType(n1, n2) { - if ((process.env.NODE_ENV !== 'production') && - n2.shapeFlag & 6 /* COMPONENT */ && - hmrDirtyComponents.has(n2.type)) { - // HMR only: if the component has been hot-updated, force a reload. - return false; + // missing but optional + if (value == null && !prop.required) { + return; } - return n1.type === n2.type && n1.key === n2.key; -} -let vnodeArgsTransformer; -/** - * Internal API for registering an arguments transform for createVNode - * used for creating stubs in the test-utils - * It is *internal* but needs to be exposed for test-utils to pick up proper - * typings - */ -function transformVNodeArgs(transformer) { - vnodeArgsTransformer = transformer; -} -const createVNodeWithArgsTransform = (...args) => { - return _createVNode(...(vnodeArgsTransformer - ? vnodeArgsTransformer(args, currentRenderingInstance) - : args)); -}; -const InternalObjectKey = `__vInternal`; -const normalizeKey = ({ key }) => key != null ? key : null; -const normalizeRef = ({ ref }) => { - return (ref != null - ? isArray(ref) - ? ref - : { i: currentRenderingInstance, r: ref } - : null); -}; -const createVNode = ((process.env.NODE_ENV !== 'production') - ? createVNodeWithArgsTransform - : _createVNode); -function _createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, isBlockNode = false) { - if (!type || type === NULL_DYNAMIC_COMPONENT) { - if ((process.env.NODE_ENV !== 'production') && !type) { - warn(`Invalid vnode type when creating vnode: ${type}.`); + // type check + if (type != null && type !== true) { + let isValid = false; + const types = isArray(type) ? type : [type]; + const expectedTypes = []; + // value is valid as long as one of the specified types match + for (let i = 0; i < types.length && !isValid; i++) { + const { valid, expectedType } = assertType(value, types[i]); + expectedTypes.push(expectedType || ''); + isValid = valid; } - type = Comment; - } - if (isVNode(type)) { - // createVNode receiving an existing vnode. This happens in cases like - // - // #2078 make sure to merge refs during the clone instead of overwriting it - const cloned = cloneVNode(type, props, true /* mergeRef: true */); - if (children) { - normalizeChildren(cloned, children); + if (!isValid) { + warn(getInvalidTypeMessage(name, value, expectedTypes)); + return; } - return cloned; } - // class component normalization. - if (isClassComponent(type)) { - type = type.__vccOpts; + // custom validator + if (validator && !validator(value)) { + warn('Invalid prop: custom validator check failed for prop "' + name + '".'); } - // class & style normalization. - if (props) { - // for reactive or proxy objects, we need to clone it to enable mutation. - if (isProxy(props) || InternalObjectKey in props) { - props = extend({}, props); - } - let { class: klass, style } = props; - if (klass && !isString(klass)) { - props.class = normalizeClass(klass); - } - if (isObject(style)) { - // reactive state objects need to be cloned since they are likely to be - // mutated - if (isProxy(style) && !isArray(style)) { - style = extend({}, style); - } - props.style = normalizeStyle(style); +} +const isSimpleType = /*#__PURE__*/ makeMap('String,Number,Boolean,Function,Symbol'); +/** + * dev only + */ +function assertType(value, type) { + let valid; + const expectedType = getType(type); + if (isSimpleType(expectedType)) { + const t = typeof value; + valid = t === expectedType.toLowerCase(); + // for primitive wrapper objects + if (!valid && t === 'object') { + valid = value instanceof type; } } - // encode the vnode type information into a bitmap - const shapeFlag = isString(type) - ? 1 /* ELEMENT */ - : isSuspense(type) - ? 128 /* SUSPENSE */ - : isTeleport(type) - ? 64 /* TELEPORT */ - : isObject(type) - ? 4 /* STATEFUL_COMPONENT */ - : isFunction(type) - ? 2 /* FUNCTIONAL_COMPONENT */ - : 0; - if ((process.env.NODE_ENV !== 'production') && shapeFlag & 4 /* STATEFUL_COMPONENT */ && isProxy(type)) { - type = toRaw(type); - warn(`Vue received a Component which was made a reactive object. This can ` + - `lead to unnecessary performance overhead, and should be avoided by ` + - `marking the component with \`markRaw\` or using \`shallowRef\` ` + - `instead of \`ref\`.`, `\nComponent that was made reactive: `, type); - } - const vnode = { - __v_isVNode: true, - ["__v_skip" /* SKIP */]: true, - type, - props, - key: props && normalizeKey(props), - ref: props && normalizeRef(props), - scopeId: currentScopeId, - children: null, - component: null, - suspense: null, - ssContent: null, - ssFallback: null, - dirs: null, - transition: null, - el: null, - anchor: null, - target: null, - targetAnchor: null, - staticCount: 0, - shapeFlag, - patchFlag, - dynamicProps, - dynamicChildren: null, - appContext: null - }; - // validate key - if ((process.env.NODE_ENV !== 'production') && vnode.key !== vnode.key) { - warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type); + else if (expectedType === 'Object') { + valid = isObject(value); } - normalizeChildren(vnode, children); - // normalize suspense children - if ( shapeFlag & 128 /* SUSPENSE */) { - const { content, fallback } = normalizeSuspenseChildren(vnode); - vnode.ssContent = content; - vnode.ssFallback = fallback; + else if (expectedType === 'Array') { + valid = isArray(value); } - if (shouldTrack$1 > 0 && - // avoid a block node from tracking itself - !isBlockNode && - // has current parent block - currentBlock && - // presence of a patch flag indicates this node needs patching on updates. - // component nodes also should always be patched, because even if the - // component doesn't need to update, it needs to persist the instance on to - // the next vnode so that it can be properly unmounted later. - (patchFlag > 0 || shapeFlag & 6 /* COMPONENT */) && - // the EVENTS flag is only for hydration and if it is the only flag, the - // vnode should not be considered dynamic due to handler caching. - patchFlag !== 32 /* HYDRATE_EVENTS */) { - currentBlock.push(vnode); + else { + valid = value instanceof type; } - return vnode; -} -function cloneVNode(vnode, extraProps, mergeRef = false) { - // This is intentionally NOT using spread or extend to avoid the runtime - // key enumeration cost. - const { props, ref, patchFlag } = vnode; - const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props; return { - __v_isVNode: true, - ["__v_skip" /* SKIP */]: true, - type: vnode.type, - props: mergedProps, - key: mergedProps && normalizeKey(mergedProps), - ref: extraProps && extraProps.ref - ? // #2078 in the case of - // if the vnode itself already has a ref, cloneVNode will need to merge - // the refs so the single vnode can be set on multiple refs - mergeRef && ref - ? isArray(ref) - ? ref.concat(normalizeRef(extraProps)) - : [ref, normalizeRef(extraProps)] - : normalizeRef(extraProps) - : ref, - scopeId: vnode.scopeId, - children: vnode.children, - target: vnode.target, - targetAnchor: vnode.targetAnchor, - staticCount: vnode.staticCount, - shapeFlag: vnode.shapeFlag, - // if the vnode is cloned with extra props, we can no longer assume its - // existing patch flag to be reliable and need to add the FULL_PROPS flag. - // note: perserve flag for fragments since they use the flag for children - // fast paths only. - patchFlag: extraProps && vnode.type !== Fragment - ? patchFlag === -1 // hoisted node - ? 16 /* FULL_PROPS */ - : patchFlag | 16 /* FULL_PROPS */ - : patchFlag, - dynamicProps: vnode.dynamicProps, - dynamicChildren: vnode.dynamicChildren, - appContext: vnode.appContext, - dirs: vnode.dirs, - transition: vnode.transition, - // These should technically only be non-null on mounted VNodes. However, - // they *should* be copied for kept-alive vnodes. So we just always copy - // them since them being non-null during a mount doesn't affect the logic as - // they will simply be overwritten. - component: vnode.component, - suspense: vnode.suspense, - ssContent: vnode.ssContent && cloneVNode(vnode.ssContent), - ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback), - el: vnode.el, - anchor: vnode.anchor + valid, + expectedType }; } /** - * @private + * dev only */ -function createTextVNode(text = ' ', flag = 0) { - return createVNode(Text, null, text, flag); -} -/** - * @private - */ -function createStaticVNode(content, numberOfNodes) { - // A static vnode can contain multiple stringified elements, and the number - // of elements is necessary for hydration. - const vnode = createVNode(Static, null, content); - vnode.staticCount = numberOfNodes; - return vnode; +function getInvalidTypeMessage(name, value, expectedTypes) { + let message = `Invalid prop: type check failed for prop "${name}".` + + ` Expected ${expectedTypes.map(capitalize).join(', ')}`; + const expectedType = expectedTypes[0]; + const receivedType = toRawType(value); + const expectedValue = styleValue(value, expectedType); + const receivedValue = styleValue(value, receivedType); + // check if we need to specify expected value + if (expectedTypes.length === 1 && + isExplicable(expectedType) && + !isBoolean(expectedType, receivedType)) { + message += ` with value ${expectedValue}`; + } + message += `, got ${receivedType} `; + // check if we need to specify received value + if (isExplicable(receivedType)) { + message += `with value ${receivedValue}.`; + } + return message; } /** - * @private + * dev only */ -function createCommentVNode(text = '', -// when used as the v-else branch, the comment node must be created as a -// block to ensure correct updates. -asBlock = false) { - return asBlock - ? (openBlock(), createBlock(Comment, null, text)) - : createVNode(Comment, null, text); -} -function normalizeVNode(child) { - if (child == null || typeof child === 'boolean') { - // empty placeholder - return createVNode(Comment); - } - else if (isArray(child)) { - // fragment - return createVNode(Fragment, null, child); +function styleValue(value, type) { + if (type === 'String') { + return `"${value}"`; } - else if (typeof child === 'object') { - // already vnode, this should be the most common since compiled templates - // always produce all-vnode children arrays - return child.el === null ? child : cloneVNode(child); + else if (type === 'Number') { + return `${Number(value)}`; } else { - // strings and numbers - return createVNode(Text, null, String(child)); + return `${value}`; } } -// optimized normalization for template-compiled render fns -function cloneIfMounted(child) { - return child.el === null ? child : cloneVNode(child); +/** + * dev only + */ +function isExplicable(type) { + const explicitTypes = ['string', 'number', 'boolean']; + return explicitTypes.some(elem => type.toLowerCase() === elem); } -function normalizeChildren(vnode, children) { - let type = 0; - const { shapeFlag } = vnode; - if (children == null) { - children = null; - } - else if (isArray(children)) { - type = 16 /* ARRAY_CHILDREN */; - } - else if (typeof children === 'object') { - if (shapeFlag & 1 /* ELEMENT */ || shapeFlag & 64 /* TELEPORT */) { - // Normalize slot to plain children for plain element and Teleport - const slot = children.default; - if (slot) { - // _c marker is added by withCtx() indicating this is a compiled slot - slot._c && setCompiledSlotRendering(1); - normalizeChildren(vnode, slot()); - slot._c && setCompiledSlotRendering(-1); - } - return; +/** + * dev only + */ +function isBoolean(...args) { + return args.some(elem => elem.toLowerCase() === 'boolean'); +} + +function injectHook(type, hook, target = currentInstance, prepend = false) { + if (target) { + const hooks = target[type] || (target[type] = []); + // cache the error handling wrapper for injected hooks so the same hook + // can be properly deduped by the scheduler. "__weh" stands for "with error + // handling". + const wrappedHook = hook.__weh || + (hook.__weh = (...args) => { + if (target.isUnmounted) { + return; + } + // disable tracking inside all lifecycle hooks + // since they can potentially be called inside effects. + pauseTracking(); + // Set currentInstance during hook invocation. + // This assumes the hook does not synchronously trigger other hooks, which + // can only be false when the user does something really funky. + setCurrentInstance(target); + const res = callWithAsyncErrorHandling(hook, target, type, args); + setCurrentInstance(null); + resetTracking(); + return res; + }); + if (prepend) { + hooks.unshift(wrappedHook); } else { - type = 32 /* SLOTS_CHILDREN */; - const slotFlag = children._; - if (!slotFlag && !(InternalObjectKey in children)) { - children._ctx = currentRenderingInstance; - } - else if (slotFlag === 3 /* FORWARDED */ && currentRenderingInstance) { - // a child component receives forwarded slots from the parent. - // its slot type is determined by its parent's slot type. - if (currentRenderingInstance.vnode.patchFlag & 1024 /* DYNAMIC_SLOTS */) { - children._ = 2 /* DYNAMIC */; - vnode.patchFlag |= 1024 /* DYNAMIC_SLOTS */; - } - else { - children._ = 1 /* STABLE */; - } - } + hooks.push(wrappedHook); } + return wrappedHook; } - else if (isFunction(children)) { - children = { default: children, _ctx: currentRenderingInstance }; - type = 32 /* SLOTS_CHILDREN */; + else if ((process.env.NODE_ENV !== 'production')) { + const apiName = toHandlerKey(ErrorTypeStrings[type].replace(/ hook$/, '')); + warn(`${apiName} is called when there is no active component instance to be ` + + `associated with. ` + + `Lifecycle injection APIs can only be used during execution of setup().` + + ( ` If you are using async setup(), make sure to register lifecycle ` + + `hooks before the first await statement.` + )); } - else { - children = String(children); - // force teleport children to array so it can be moved around - if (shapeFlag & 64 /* TELEPORT */) { - type = 16 /* ARRAY_CHILDREN */; - children = [createTextVNode(children)]; +} +const createHook = (lifecycle) => (hook, target = currentInstance) => +// post-create lifecycle registrations are noops during SSR +!isInSSRComponentSetup && injectHook(lifecycle, hook, target); +const onBeforeMount = createHook("bm" /* BEFORE_MOUNT */); +const onMounted = createHook("m" /* MOUNTED */); +const onBeforeUpdate = createHook("bu" /* BEFORE_UPDATE */); +const onUpdated = createHook("u" /* UPDATED */); +const onBeforeUnmount = createHook("bum" /* BEFORE_UNMOUNT */); +const onUnmounted = createHook("um" /* UNMOUNTED */); +const onRenderTriggered = createHook("rtg" /* RENDER_TRIGGERED */); +const onRenderTracked = createHook("rtc" /* RENDER_TRACKED */); +const onErrorCaptured = (hook, target = currentInstance) => { + injectHook("ec" /* ERROR_CAPTURED */, hook, target); +}; + +// Simple effect. +function watchEffect(effect, options) { + return doWatch(effect, null, options); +} +// initial value for watchers to trigger on undefined initial values +const INITIAL_WATCHER_VALUE = {}; +// implementation +function watch(source, cb, options) { + if ((process.env.NODE_ENV !== 'production') && !isFunction(cb)) { + warn(`\`watch(fn, options?)\` signature has been moved to a separate API. ` + + `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + + `supports \`watch(source, cb, options?) signature.`); + } + return doWatch(source, cb, options); +} +function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ, instance = currentInstance) { + if ((process.env.NODE_ENV !== 'production') && !cb) { + if (immediate !== undefined) { + warn(`watch() "immediate" option is only respected when using the ` + + `watch(source, callback, options?) signature.`); } - else { - type = 8 /* TEXT_CHILDREN */; + if (deep !== undefined) { + warn(`watch() "deep" option is only respected when using the ` + + `watch(source, callback, options?) signature.`); } } - vnode.children = children; - vnode.shapeFlag |= type; -} -function mergeProps(...args) { - const ret = extend({}, args[0]); - for (let i = 1; i < args.length; i++) { - const toMerge = args[i]; - for (const key in toMerge) { - if (key === 'class') { - if (ret.class !== toMerge.class) { - ret.class = normalizeClass([ret.class, toMerge.class]); - } + const warnInvalidSource = (s) => { + warn(`Invalid watch source: `, s, `A watch source can only be a getter/effect function, a ref, ` + + `a reactive object, or an array of these types.`); + }; + let getter; + let forceTrigger = false; + if (isRef(source)) { + getter = () => source.value; + forceTrigger = !!source._shallow; + } + else if (isReactive(source)) { + getter = () => source; + deep = true; + } + else if (isArray(source)) { + getter = () => source.map(s => { + if (isRef(s)) { + return s.value; } - else if (key === 'style') { - ret.style = normalizeStyle([ret.style, toMerge.style]); + else if (isReactive(s)) { + return traverse(s); } - else if (isOn(key)) { - const existing = ret[key]; - const incoming = toMerge[key]; - if (existing !== incoming) { - ret[key] = existing - ? [].concat(existing, toMerge[key]) - : incoming; - } + else if (isFunction(s)) { + return callWithErrorHandling(s, instance, 2 /* WATCH_GETTER */); } else { - ret[key] = toMerge[key]; + (process.env.NODE_ENV !== 'production') && warnInvalidSource(s); } + }); + } + else if (isFunction(source)) { + if (cb) { + // getter with cb + getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */); + } + else { + // no cb -> simple effect + getter = () => { + if (instance && instance.isUnmounted) { + return; + } + if (cleanup) { + cleanup(); + } + return callWithErrorHandling(source, instance, 3 /* WATCH_CALLBACK */, [onInvalidate]); + }; } } - return ret; -} - -function initProps(instance, rawProps, isStateful, // result of bitwise flag comparison -isSSR = false) { - const props = {}; - const attrs = {}; - def(attrs, InternalObjectKey, 1); - setFullProps(instance, rawProps, props, attrs); - // validation - if ((process.env.NODE_ENV !== 'production')) { - validateProps(props, instance); - } - if (isStateful) { - // stateful - instance.props = isSSR ? props : shallowReactive(props); - } else { - if (!instance.type.props) { - // functional w/ optional props, props === attrs - instance.props = attrs; - } - else { - // functional w/ declared props - instance.props = props; - } + getter = NOOP; + (process.env.NODE_ENV !== 'production') && warnInvalidSource(source); } - instance.attrs = attrs; -} -function updateProps(instance, rawProps, rawPrevProps, optimized) { - const { props, attrs, vnode: { patchFlag } } = instance; - const rawCurrentProps = toRaw(props); - const [options] = instance.propsOptions; - if ( - // always force full diff if hmr is enabled - !((process.env.NODE_ENV !== 'production') && instance.type.__hmrId) && - (optimized || patchFlag > 0) && - !(patchFlag & 16 /* FULL_PROPS */)) { - if (patchFlag & 8 /* PROPS */) { - // Compiler-generated props & no keys change, just set the updated - // the props. - const propsToUpdate = instance.vnode.dynamicProps; - for (let i = 0; i < propsToUpdate.length; i++) { - const key = propsToUpdate[i]; - // PROPS flag guarantees rawProps to be non-null - const value = rawProps[key]; - if (options) { - // attr / props separation was done on init and will be consistent - // in this code path, so just check if attrs have it. - if (hasOwn(attrs, key)) { - attrs[key] = value; - } - else { - const camelizedKey = camelize(key); - props[camelizedKey] = resolvePropValue(options, rawCurrentProps, camelizedKey, value, instance); - } - } - else { - attrs[key] = value; - } - } - } + if (cb && deep) { + const baseGetter = getter; + getter = () => traverse(baseGetter()); } - else { - // full props update. - setFullProps(instance, rawProps, props, attrs); - // in case of dynamic props, check if we need to delete keys from - // the props object - let kebabKey; - for (const key in rawCurrentProps) { - if (!rawProps || - // for camelCase - (!hasOwn(rawProps, key) && - // it's possible the original props was passed in as kebab-case - // and converted to camelCase (#955) - ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey)))) { - if (options) { - if (rawPrevProps && - // for camelCase - (rawPrevProps[key] !== undefined || - // for kebab-case - rawPrevProps[kebabKey] !== undefined)) { - props[key] = resolvePropValue(options, rawProps || EMPTY_OBJ, key, undefined, instance); - } - } - else { - delete props[key]; - } - } + let cleanup; + const onInvalidate = (fn) => { + cleanup = runner.options.onStop = () => { + callWithErrorHandling(fn, instance, 4 /* WATCH_CLEANUP */); + }; + }; + let oldValue = isArray(source) ? [] : INITIAL_WATCHER_VALUE; + const job = () => { + if (!runner.active) { + return; } - // in the case of functional component w/o props declaration, props and - // attrs point to the same object so it should already have been updated. - if (attrs !== rawCurrentProps) { - for (const key in attrs) { - if (!rawProps || !hasOwn(rawProps, key)) { - delete attrs[key]; + if (cb) { + // watch(source, cb) + const newValue = runner(); + if (deep || forceTrigger || hasChanged(newValue, oldValue)) { + // cleanup before running cb again + if (cleanup) { + cleanup(); } + callWithAsyncErrorHandling(cb, instance, 3 /* WATCH_CALLBACK */, [ + newValue, + // pass undefined as the old value when it's changed for the first time + oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue, + onInvalidate + ]); + oldValue = newValue; } } - } - // trigger updates for $attrs in case it's used in component slots - trigger(instance, "set" /* SET */, '$attrs'); - if ((process.env.NODE_ENV !== 'production') && rawProps) { - validateProps(props, instance); - } -} -function setFullProps(instance, rawProps, props, attrs) { - const [options, needCastKeys] = instance.propsOptions; - if (rawProps) { - for (const key in rawProps) { - const value = rawProps[key]; - // key, ref are reserved and never passed down - if (isReservedProp(key)) { - continue; - } - // prop option names are camelized during normalization, so to support - // kebab -> camel conversion here we need to camelize the key. - let camelKey; - if (options && hasOwn(options, (camelKey = camelize(key)))) { - props[camelKey] = value; - } - else if (!isEmitListener(instance.emitsOptions, key)) { - // Any non-declared (either as a prop or an emitted event) props are put - // into a separate `attrs` object for spreading. Make sure to preserve - // original key casing - attrs[key] = value; - } + else { + // watchEffect + runner(); } + }; + // important: mark the job as a watcher callback so that scheduler knows + // it is allowed to self-trigger (#1727) + job.allowRecurse = !!cb; + let scheduler; + if (flush === 'sync') { + scheduler = job; } - if (needCastKeys) { - const rawCurrentProps = toRaw(props); - for (let i = 0; i < needCastKeys.length; i++) { - const key = needCastKeys[i]; - props[key] = resolvePropValue(options, rawCurrentProps, key, rawCurrentProps[key], instance); - } + else if (flush === 'post') { + scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); } -} -function resolvePropValue(options, props, key, value, instance) { - const opt = options[key]; - if (opt != null) { - const hasDefault = hasOwn(opt, 'default'); - // default values - if (hasDefault && value === undefined) { - const defaultValue = opt.default; - if (opt.type !== Function && isFunction(defaultValue)) { - setCurrentInstance(instance); - value = defaultValue(props); - setCurrentInstance(null); + else { + // default: 'pre' + scheduler = () => { + if (!instance || instance.isMounted) { + queuePreFlushCb(job); } else { - value = defaultValue; - } - } - // boolean casting - if (opt[0 /* shouldCast */]) { - if (!hasOwn(props, key) && !hasDefault) { - value = false; - } - else if (opt[1 /* shouldCastTrue */] && - (value === '' || value === hyphenate(key))) { - value = true; + // with 'pre' option, the first call must happen before + // the component is mounted so it is called synchronously. + job(); } - } - } - return value; -} -function normalizePropsOptions(comp, appContext, asMixin = false) { - const appId = appContext.app ? appContext.app._uid : -1; - const cache = comp.__props || (comp.__props = {}); - const cached = cache[appId]; - if (cached) { - return cached; - } - const raw = comp.props; - const normalized = {}; - const needCastKeys = []; - // apply mixin/extends props - let hasExtends = false; - if (__VUE_OPTIONS_API__ && !isFunction(comp)) { - const extendProps = (raw) => { - hasExtends = true; - const [props, keys] = normalizePropsOptions(raw, appContext, true); - extend(normalized, props); - if (keys) - needCastKeys.push(...keys); }; - if (!asMixin && appContext.mixins.length) { - appContext.mixins.forEach(extendProps); - } - if (comp.extends) { - extendProps(comp.extends); + } + const runner = effect(getter, { + lazy: true, + onTrack, + onTrigger, + scheduler + }); + recordInstanceBoundEffect(runner); + // initial run + if (cb) { + if (immediate) { + job(); } - if (comp.mixins) { - comp.mixins.forEach(extendProps); + else { + oldValue = runner(); } } - if (!raw && !hasExtends) { - return (cache[appId] = EMPTY_ARR); + else if (flush === 'post') { + queuePostRenderEffect(runner, instance && instance.suspense); } - if (isArray(raw)) { - for (let i = 0; i < raw.length; i++) { - if ((process.env.NODE_ENV !== 'production') && !isString(raw[i])) { - warn(`props must be strings when using array syntax.`, raw[i]); - } - const normalizedKey = camelize(raw[i]); - if (validatePropName(normalizedKey)) { - normalized[normalizedKey] = EMPTY_OBJ; - } - } + else { + runner(); } - else if (raw) { - if ((process.env.NODE_ENV !== 'production') && !isObject(raw)) { - warn(`invalid props options`, raw); + return () => { + stop(runner); + if (instance) { + remove(instance.effects, runner); } - for (const key in raw) { - const normalizedKey = camelize(key); - if (validatePropName(normalizedKey)) { - const opt = raw[key]; - const prop = (normalized[normalizedKey] = - isArray(opt) || isFunction(opt) ? { type: opt } : opt); - if (prop) { - const booleanIndex = getTypeIndex(Boolean, prop.type); - const stringIndex = getTypeIndex(String, prop.type); - prop[0 /* shouldCast */] = booleanIndex > -1; - prop[1 /* shouldCastTrue */] = - stringIndex < 0 || booleanIndex < stringIndex; - // if the prop needs boolean casting or default value - if (booleanIndex > -1 || hasOwn(prop, 'default')) { - needCastKeys.push(normalizedKey); - } - } - } - } - } - return (cache[appId] = [normalized, needCastKeys]); -} -// use function string name to check type constructors -// so that it works across vms / iframes. -function getType(ctor) { - const match = ctor && ctor.toString().match(/^\s*function (\w+)/); - return match ? match[1] : ''; -} -function isSameType(a, b) { - return getType(a) === getType(b); -} -function getTypeIndex(type, expectedTypes) { - if (isArray(expectedTypes)) { - for (let i = 0, len = expectedTypes.length; i < len; i++) { - if (isSameType(expectedTypes[i], type)) { - return i; - } - } - } - else if (isFunction(expectedTypes)) { - return isSameType(expectedTypes, type) ? 0 : -1; - } - return -1; -} -/** - * dev only - */ -function validateProps(props, instance) { - const rawValues = toRaw(props); - const options = instance.propsOptions[0]; - for (const key in options) { - let opt = options[key]; - if (opt == null) - continue; - validateProp(key, rawValues[key], opt, !hasOwn(rawValues, key)); - } + }; } -/** - * dev only - */ -function validatePropName(key) { - if (key[0] !== '$') { - return true; - } - else if ((process.env.NODE_ENV !== 'production')) { - warn(`Invalid prop name: "${key}" is a reserved property.`); - } - return false; +// this.$watch +function instanceWatch(source, cb, options) { + const publicThis = this.proxy; + const getter = isString(source) + ? () => publicThis[source] + : source.bind(publicThis); + return doWatch(getter, cb.bind(publicThis), options, this); } -/** - * dev only - */ -function validateProp(name, value, prop, isAbsent) { - const { type, required, validator } = prop; - // required! - if (required && isAbsent) { - warn('Missing required prop: "' + name + '"'); - return; - } - // missing but optional - if (value == null && !prop.required) { - return; - } - // type check - if (type != null && type !== true) { - let isValid = false; - const types = isArray(type) ? type : [type]; - const expectedTypes = []; - // value is valid as long as one of the specified types match - for (let i = 0; i < types.length && !isValid; i++) { - const { valid, expectedType } = assertType(value, types[i]); - expectedTypes.push(expectedType || ''); - isValid = valid; - } - if (!isValid) { - warn(getInvalidTypeMessage(name, value, expectedTypes)); - return; - } +function traverse(value, seen = new Set()) { + if (!isObject(value) || seen.has(value)) { + return value; } - // custom validator - if (validator && !validator(value)) { - warn('Invalid prop: custom validator check failed for prop "' + name + '".'); + seen.add(value); + if (isRef(value)) { + traverse(value.value, seen); } -} -const isSimpleType = /*#__PURE__*/ makeMap('String,Number,Boolean,Function,Symbol'); -/** - * dev only - */ -function assertType(value, type) { - let valid; - const expectedType = getType(type); - if (isSimpleType(expectedType)) { - const t = typeof value; - valid = t === expectedType.toLowerCase(); - // for primitive wrapper objects - if (!valid && t === 'object') { - valid = value instanceof type; + else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + traverse(value[i], seen); } } - else if (expectedType === 'Object') { - valid = isObject(value); - } - else if (expectedType === 'Array') { - valid = isArray(value); - } - else { - valid = value instanceof type; - } - return { - valid, - expectedType - }; -} -/** - * dev only - */ -function getInvalidTypeMessage(name, value, expectedTypes) { - let message = `Invalid prop: type check failed for prop "${name}".` + - ` Expected ${expectedTypes.map(capitalize).join(', ')}`; - const expectedType = expectedTypes[0]; - const receivedType = toRawType(value); - const expectedValue = styleValue(value, expectedType); - const receivedValue = styleValue(value, receivedType); - // check if we need to specify expected value - if (expectedTypes.length === 1 && - isExplicable(expectedType) && - !isBoolean(expectedType, receivedType)) { - message += ` with value ${expectedValue}`; - } - message += `, got ${receivedType} `; - // check if we need to specify received value - if (isExplicable(receivedType)) { - message += `with value ${receivedValue}.`; - } - return message; -} -/** - * dev only - */ -function styleValue(value, type) { - if (type === 'String') { - return `"${value}"`; - } - else if (type === 'Number') { - return `${Number(value)}`; + else if (isSet(value) || isMap(value)) { + value.forEach((v) => { + traverse(v, seen); + }); } else { - return `${value}`; - } -} -/** - * dev only - */ -function isExplicable(type) { - const explicitTypes = ['string', 'number', 'boolean']; - return explicitTypes.some(elem => type.toLowerCase() === elem); -} -/** - * dev only - */ -function isBoolean(...args) { - return args.some(elem => elem.toLowerCase() === 'boolean'); -} - -function injectHook(type, hook, target = currentInstance, prepend = false) { - if (target) { - const hooks = target[type] || (target[type] = []); - // cache the error handling wrapper for injected hooks so the same hook - // can be properly deduped by the scheduler. "__weh" stands for "with error - // handling". - const wrappedHook = hook.__weh || - (hook.__weh = (...args) => { - if (target.isUnmounted) { - return; - } - // disable tracking inside all lifecycle hooks - // since they can potentially be called inside effects. - pauseTracking(); - // Set currentInstance during hook invocation. - // This assumes the hook does not synchronously trigger other hooks, which - // can only be false when the user does something really funky. - setCurrentInstance(target); - const res = callWithAsyncErrorHandling(hook, target, type, args); - setCurrentInstance(null); - resetTracking(); - return res; - }); - if (prepend) { - hooks.unshift(wrappedHook); - } - else { - hooks.push(wrappedHook); + for (const key in value) { + traverse(value[key], seen); } - return wrappedHook; } - else if ((process.env.NODE_ENV !== 'production')) { - const apiName = `on${capitalize(ErrorTypeStrings[type].replace(/ hook$/, ''))}`; - warn(`${apiName} is called when there is no active component instance to be ` + - `associated with. ` + - `Lifecycle injection APIs can only be used during execution of setup().` + - ( ` If you are using async setup(), make sure to register lifecycle ` + - `hooks before the first await statement.` - )); - } -} -const createHook = (lifecycle) => (hook, target = currentInstance) => -// post-create lifecycle registrations are noops during SSR -!isInSSRComponentSetup && injectHook(lifecycle, hook, target); -const onBeforeMount = createHook("bm" /* BEFORE_MOUNT */); -const onMounted = createHook("m" /* MOUNTED */); -const onBeforeUpdate = createHook("bu" /* BEFORE_UPDATE */); -const onUpdated = createHook("u" /* UPDATED */); -const onBeforeUnmount = createHook("bum" /* BEFORE_UNMOUNT */); -const onUnmounted = createHook("um" /* UNMOUNTED */); -const onRenderTriggered = createHook("rtg" /* RENDER_TRIGGERED */); -const onRenderTracked = createHook("rtc" /* RENDER_TRACKED */); -const onErrorCaptured = (hook, target = currentInstance) => { - injectHook("ec" /* ERROR_CAPTURED */, hook, target); -}; + return value; +} function useTransitionState() { const state = { @@ -4215,6 +3766,11 @@ function createAppAPI(render, hydrate) { if (__VUE_OPTIONS_API__) { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin); + // global mixin with props/emits de-optimizes props/emits + // normalization caching. + if (mixin.props || mixin.emits) { + context.deopt = true; + } } else if ((process.env.NODE_ENV !== 'production')) { warn('Mixin has already been applied to target app' + @@ -5037,7 +4593,7 @@ function baseCreateRenderer(options, createHydrationFns) { if (dirs) { invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate'); } - if ((process.env.NODE_ENV !== 'production') && isHmrUpdating) { + if ((process.env.NODE_ENV !== 'production') && (true ) && isHmrUpdating) { // HMR updated, force full diff patchFlag = 0; optimized = false; @@ -5100,7 +4656,10 @@ function baseCreateRenderer(options, createHydrationFns) { const areChildrenSVG = isSVG && n2.type !== 'foreignObject'; if (dynamicChildren) { patchBlockChildren(n1.dynamicChildren, dynamicChildren, el, parentComponent, parentSuspense, areChildrenSVG); - if ((process.env.NODE_ENV !== 'production') && parentComponent && parentComponent.type.__hmrId) { + if ((process.env.NODE_ENV !== 'production') && + (true ) && + parentComponent && + parentComponent.type.__hmrId) { traverseStaticChildren(n1, n2); } } @@ -5141,6 +4700,7 @@ function baseCreateRenderer(options, createHydrationFns) { const patchProps = (el, vnode, oldProps, newProps, parentComponent, parentSuspense, isSVG) => { if (oldProps !== newProps) { for (const key in newProps) { + // empty string is not valid prop if (isReservedProp(key)) continue; const next = newProps[key]; @@ -5224,7 +4784,7 @@ function baseCreateRenderer(options, createHydrationFns) { }; const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => { const instance = (initialVNode.component = createComponentInstance(initialVNode, parentComponent, parentSuspense)); - if ((process.env.NODE_ENV !== 'production') && instance.type.__hmrId) { + if ((process.env.NODE_ENV !== 'production') && (true ) && instance.type.__hmrId) { registerHMR(instance); } if ((process.env.NODE_ENV !== 'production')) { @@ -5369,12 +4929,12 @@ function baseCreateRenderer(options, createHydrationFns) { pushWarningContext(next || instance.vnode); } if (next) { + next.el = vnode.el; updateComponentPreRender(instance, next, optimized); } else { next = vnode; } - next.el = vnode.el; // beforeUpdate hook if (bu) { invokeArrayFns(bu); @@ -5393,11 +4953,6 @@ function baseCreateRenderer(options, createHydrationFns) { } const prevTree = instance.subTree; instance.subTree = nextTree; - // reset refs - // only needed if previous patch had refs - if (instance.refs !== EMPTY_OBJ) { - instance.refs = {}; - } if ((process.env.NODE_ENV !== 'production')) { startMeasure(instance, `patch`); } @@ -5515,7 +5070,7 @@ function baseCreateRenderer(options, createHydrationFns) { } if (oldLength > newLength) { // remove old - unmountChildren(c1, parentComponent, parentSuspense, true, commonLength); + unmountChildren(c1, parentComponent, parentSuspense, true, false, commonLength); } else { // mount new @@ -5752,7 +5307,7 @@ function baseCreateRenderer(options, createHydrationFns) { hostInsert(el, container, anchor); } }; - const unmount = (vnode, parentComponent, parentSuspense, doRemove = false) => { + const unmount = (vnode, parentComponent, parentSuspense, doRemove = false, optimized = false) => { const { type, props, ref, children, dynamicChildren, shapeFlag, patchFlag, dirs } = vnode; // unset ref if (ref != null && parentComponent) { @@ -5783,13 +5338,17 @@ function baseCreateRenderer(options, createHydrationFns) { (type !== Fragment || (patchFlag > 0 && patchFlag & 64 /* STABLE_FRAGMENT */))) { // fast path for block nodes: only need to unmount dynamic children. - unmountChildren(dynamicChildren, parentComponent, parentSuspense); + unmountChildren(dynamicChildren, parentComponent, parentSuspense, false, true); } - else if (shapeFlag & 16 /* ARRAY_CHILDREN */) { + else if ((type === Fragment && + (patchFlag & 128 /* KEYED_FRAGMENT */ || + patchFlag & 256 /* UNKEYED_FRAGMENT */)) || + (!optimized && shapeFlag & 16 /* ARRAY_CHILDREN */)) { unmountChildren(children, parentComponent, parentSuspense); } - // an unmounted teleport should always remove its children - if (shapeFlag & 64 /* TELEPORT */) { + // an unmounted teleport should always remove its children if not disabled + if (shapeFlag & 64 /* TELEPORT */ && + (doRemove || !isTeleportDisabled(vnode.props))) { vnode.type.remove(vnode, internals); } if (doRemove) { @@ -5848,7 +5407,7 @@ function baseCreateRenderer(options, createHydrationFns) { hostRemove(end); }; const unmountComponent = (instance, parentSuspense, doRemove) => { - if ((process.env.NODE_ENV !== 'production') && instance.type.__hmrId) { + if ((process.env.NODE_ENV !== 'production') && (true ) && instance.type.__hmrId) { unregisterHMR(instance); } const { bum, effects, update, subTree, um } = instance; @@ -5893,9 +5452,9 @@ function baseCreateRenderer(options, createHydrationFns) { devtoolsComponentRemoved(instance); } }; - const unmountChildren = (children, parentComponent, parentSuspense, doRemove = false, start = 0) => { + const unmountChildren = (children, parentComponent, parentSuspense, doRemove = false, optimized = false, start = 0) => { for (let i = start; i < children.length; i++) { - unmount(children[i], parentComponent, parentSuspense, doRemove); + unmount(children[i], parentComponent, parentSuspense, doRemove, optimized); } }; const getNextHostNode = vnode => { @@ -5907,39 +5466,6 @@ function baseCreateRenderer(options, createHydrationFns) { } return hostNextSibling((vnode.anchor || vnode.el)); }; - /** - * #1156 - * When a component is HMR-enabled, we need to make sure that all static nodes - * inside a block also inherit the DOM element from the previous tree so that - * HMR updates (which are full updates) can retrieve the element for patching. - * - * #2080 - * Inside keyed `template` fragment static children, if a fragment is moved, - * the children will always moved so that need inherit el form previous nodes - * to ensure correct moved position. - */ - const traverseStaticChildren = (n1, n2, shallow = false) => { - const ch1 = n1.children; - const ch2 = n2.children; - if (isArray(ch1) && isArray(ch2)) { - for (let i = 0; i < ch1.length; i++) { - // this is only called in the optimized path so array children are - // guaranteed to be vnodes - const c1 = ch1[i]; - const c2 = (ch2[i] = cloneIfMounted(ch2[i])); - if (c2.shapeFlag & 1 /* ELEMENT */ && !c2.dynamicChildren) { - if (c2.patchFlag <= 0 || c2.patchFlag === 32 /* HYDRATE_EVENTS */) { - c2.el = c1.el; - } - if (!shallow) - traverseStaticChildren(c1, c2); - } - if ((process.env.NODE_ENV !== 'production') && c2.type === Comment) { - c2.el = c1.el; - } - } - } - }; const render = (vnode, container) => { if (vnode == null) { if (container._vnode) { @@ -5981,6 +5507,42 @@ function invokeVNodeHook(hook, instance, vnode, prevVNode = null) { prevVNode ]); } +/** + * #1156 + * When a component is HMR-enabled, we need to make sure that all static nodes + * inside a block also inherit the DOM element from the previous tree so that + * HMR updates (which are full updates) can retrieve the element for patching. + * + * #2080 + * Inside keyed `template` fragment static children, if a fragment is moved, + * the children will always moved so that need inherit el form previous nodes + * to ensure correct moved position. + */ +function traverseStaticChildren(n1, n2, shallow = false) { + const ch1 = n1.children; + const ch2 = n2.children; + if (isArray(ch1) && isArray(ch2)) { + for (let i = 0; i < ch1.length; i++) { + // this is only called in the optimized path so array children are + // guaranteed to be vnodes + const c1 = ch1[i]; + let c2 = ch2[i]; + if (c2.shapeFlag & 1 /* ELEMENT */ && !c2.dynamicChildren) { + if (c2.patchFlag <= 0 || c2.patchFlag === 32 /* HYDRATE_EVENTS */) { + c2 = ch2[i] = cloneIfMounted(ch2[i]); + c2.el = c1.el; + } + if (!shallow) + traverseStaticChildren(c1, c2); + } + // also inherit for comment nodes, but not placeholders (e.g. v-if which + // would have received .el during block patch) + if ((process.env.NODE_ENV !== 'production') && c2.type === Comment && !c2.el) { + c2.el = c1.el; + } + } + } +} // https://en.wikipedia.org/wiki/Longest_increasing_subsequence function getSequence(arr) { const p = arr.slice(); @@ -6024,210 +5586,667 @@ function getSequence(arr) { return result; } -// Simple effect. -function watchEffect(effect, options) { - return doWatch(effect, null, options); -} -// initial value for watchers to trigger on undefined initial values -const INITIAL_WATCHER_VALUE = {}; -// implementation -function watch(source, cb, options) { - if ((process.env.NODE_ENV !== 'production') && !isFunction(cb)) { - warn(`\`watch(fn, options?)\` signature has been moved to a separate API. ` + - `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + - `supports \`watch(source, cb, options?) signature.`); - } - return doWatch(source, cb, options); -} -function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ, instance = currentInstance) { - if ((process.env.NODE_ENV !== 'production') && !cb) { - if (immediate !== undefined) { - warn(`watch() "immediate" option is only respected when using the ` + - `watch(source, callback, options?) signature.`); +const isTeleport = (type) => type.__isTeleport; +const isTeleportDisabled = (props) => props && (props.disabled || props.disabled === ''); +const resolveTarget = (props, select) => { + const targetSelector = props && props.to; + if (isString(targetSelector)) { + if (!select) { + (process.env.NODE_ENV !== 'production') && + warn(`Current renderer does not support string target for Teleports. ` + + `(missing querySelector renderer option)`); + return null; } - if (deep !== undefined) { - warn(`watch() "deep" option is only respected when using the ` + - `watch(source, callback, options?) signature.`); + else { + const target = select(targetSelector); + if (!target) { + (process.env.NODE_ENV !== 'production') && + warn(`Failed to locate Teleport target with selector "${targetSelector}". ` + + `Note the target element must exist before the component is mounted - ` + + `i.e. the target cannot be rendered by the component itself, and ` + + `ideally should be outside of the entire Vue component tree.`); + } + return target; } } - const warnInvalidSource = (s) => { - warn(`Invalid watch source: `, s, `A watch source can only be a getter/effect function, a ref, ` + - `a reactive object, or an array of these types.`); - }; - let getter; - const isRefSource = isRef(source); - if (isRefSource) { - getter = () => source.value; - } - else if (isReactive(source)) { - getter = () => source; - deep = true; + else { + if ((process.env.NODE_ENV !== 'production') && !targetSelector && !isTeleportDisabled(props)) { + warn(`Invalid Teleport target: ${targetSelector}`); + } + return targetSelector; } - else if (isArray(source)) { - getter = () => source.map(s => { - if (isRef(s)) { - return s.value; +}; +const TeleportImpl = { + __isTeleport: true, + process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals) { + const { mc: mountChildren, pc: patchChildren, pbc: patchBlockChildren, o: { insert, querySelector, createText, createComment } } = internals; + const disabled = isTeleportDisabled(n2.props); + const { shapeFlag, children } = n2; + if (n1 == null) { + // insert anchors in the main view + const placeholder = (n2.el = (process.env.NODE_ENV !== 'production') + ? createComment('teleport start') + : createText('')); + const mainAnchor = (n2.anchor = (process.env.NODE_ENV !== 'production') + ? createComment('teleport end') + : createText('')); + insert(placeholder, container, anchor); + insert(mainAnchor, container, anchor); + const target = (n2.target = resolveTarget(n2.props, querySelector)); + const targetAnchor = (n2.targetAnchor = createText('')); + if (target) { + insert(targetAnchor, target); } - else if (isReactive(s)) { - return traverse(s); + else if ((process.env.NODE_ENV !== 'production') && !disabled) { + warn('Invalid Teleport target on mount:', target, `(${typeof target})`); } - else if (isFunction(s)) { - return callWithErrorHandling(s, instance, 2 /* WATCH_GETTER */); + const mount = (container, anchor) => { + // Teleport *always* has Array children. This is enforced in both the + // compiler and vnode children normalization. + if (shapeFlag & 16 /* ARRAY_CHILDREN */) { + mountChildren(children, container, anchor, parentComponent, parentSuspense, isSVG, optimized); + } + }; + if (disabled) { + mount(container, mainAnchor); } - else { - (process.env.NODE_ENV !== 'production') && warnInvalidSource(s); + else if (target) { + mount(target, targetAnchor); } - }); - } - else if (isFunction(source)) { - if (cb) { - // getter with cb - getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */); } else { - // no cb -> simple effect - getter = () => { - if (instance && instance.isUnmounted) { - return; + // update content + n2.el = n1.el; + const mainAnchor = (n2.anchor = n1.anchor); + const target = (n2.target = n1.target); + const targetAnchor = (n2.targetAnchor = n1.targetAnchor); + const wasDisabled = isTeleportDisabled(n1.props); + const currentContainer = wasDisabled ? container : target; + const currentAnchor = wasDisabled ? mainAnchor : targetAnchor; + if (n2.dynamicChildren) { + // fast path when the teleport happens to be a block root + patchBlockChildren(n1.dynamicChildren, n2.dynamicChildren, currentContainer, parentComponent, parentSuspense, isSVG); + // even in block tree mode we need to make sure all root-level nodes + // in the teleport inherit previous DOM references so that they can + // be moved in future patches. + traverseStaticChildren(n1, n2, true); + } + else if (!optimized) { + patchChildren(n1, n2, currentContainer, currentAnchor, parentComponent, parentSuspense, isSVG); + } + if (disabled) { + if (!wasDisabled) { + // enabled -> disabled + // move into main container + moveTeleport(n2, container, mainAnchor, internals, 1 /* TOGGLE */); } - if (cleanup) { - cleanup(); + } + else { + // target changed + if ((n2.props && n2.props.to) !== (n1.props && n1.props.to)) { + const nextTarget = (n2.target = resolveTarget(n2.props, querySelector)); + if (nextTarget) { + moveTeleport(n2, nextTarget, null, internals, 0 /* TARGET_CHANGE */); + } + else if ((process.env.NODE_ENV !== 'production')) { + warn('Invalid Teleport target on update:', target, `(${typeof target})`); + } } - return callWithErrorHandling(source, instance, 3 /* WATCH_CALLBACK */, [onInvalidate]); - }; + else if (wasDisabled) { + // disabled -> enabled + // move into teleport target + moveTeleport(n2, target, targetAnchor, internals, 1 /* TOGGLE */); + } + } + } + }, + remove(vnode, { r: remove, o: { remove: hostRemove } }) { + const { shapeFlag, children, anchor } = vnode; + hostRemove(anchor); + if (shapeFlag & 16 /* ARRAY_CHILDREN */) { + for (let i = 0; i < children.length; i++) { + remove(children[i]); + } + } + }, + move: moveTeleport, + hydrate: hydrateTeleport +}; +function moveTeleport(vnode, container, parentAnchor, { o: { insert }, m: move }, moveType = 2 /* REORDER */) { + // move target anchor if this is a target change. + if (moveType === 0 /* TARGET_CHANGE */) { + insert(vnode.targetAnchor, container, parentAnchor); + } + const { el, anchor, shapeFlag, children, props } = vnode; + const isReorder = moveType === 2 /* REORDER */; + // move main view anchor if this is a re-order. + if (isReorder) { + insert(el, container, parentAnchor); + } + // if this is a re-order and teleport is enabled (content is in target) + // do not move children. So the opposite is: only move children if this + // is not a reorder, or the teleport is disabled + if (!isReorder || isTeleportDisabled(props)) { + // Teleport has either Array children or no children. + if (shapeFlag & 16 /* ARRAY_CHILDREN */) { + for (let i = 0; i < children.length; i++) { + move(children[i], container, parentAnchor, 2 /* REORDER */); + } + } + } + // move main view anchor if this is a re-order. + if (isReorder) { + insert(anchor, container, parentAnchor); + } +} +function hydrateTeleport(node, vnode, parentComponent, parentSuspense, optimized, { o: { nextSibling, parentNode, querySelector } }, hydrateChildren) { + const target = (vnode.target = resolveTarget(vnode.props, querySelector)); + if (target) { + // if multiple teleports rendered to the same target element, we need to + // pick up from where the last teleport finished instead of the first node + const targetNode = target._lpa || target.firstChild; + if (vnode.shapeFlag & 16 /* ARRAY_CHILDREN */) { + if (isTeleportDisabled(vnode.props)) { + vnode.anchor = hydrateChildren(nextSibling(node), vnode, parentNode(node), parentComponent, parentSuspense, optimized); + vnode.targetAnchor = targetNode; + } + else { + vnode.anchor = nextSibling(node); + vnode.targetAnchor = hydrateChildren(targetNode, vnode, target, parentComponent, parentSuspense, optimized); + } + target._lpa = + vnode.targetAnchor && nextSibling(vnode.targetAnchor); } } + return vnode.anchor && nextSibling(vnode.anchor); +} +// Force-casted public typing for h and TSX props inference +const Teleport = TeleportImpl; + +const COMPONENTS = 'components'; +const DIRECTIVES = 'directives'; +/** + * @private + */ +function resolveComponent(name) { + return resolveAsset(COMPONENTS, name) || name; +} +const NULL_DYNAMIC_COMPONENT = Symbol(); +/** + * @private + */ +function resolveDynamicComponent(component) { + if (isString(component)) { + return resolveAsset(COMPONENTS, component, false) || component; + } + else { + // invalid types will fallthrough to createVNode and raise warning + return (component || NULL_DYNAMIC_COMPONENT); + } +} +/** + * @private + */ +function resolveDirective(name) { + return resolveAsset(DIRECTIVES, name); +} +// implementation +function resolveAsset(type, name, warnMissing = true) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + // self name has highest priority + if (type === COMPONENTS) { + const selfName = Component.displayName || Component.name; + if (selfName && + (selfName === name || + selfName === camelize(name) || + selfName === capitalize(camelize(name)))) { + return Component; + } + } + const res = + // local registration + // check instance[type] first for components with mixin or extends. + resolve(instance[type] || Component[type], name) || + // global registration + resolve(instance.appContext[type], name); + if ((process.env.NODE_ENV !== 'production') && warnMissing && !res) { + warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + } + return res; + } + else if ((process.env.NODE_ENV !== 'production')) { + warn(`resolve${capitalize(type.slice(0, -1))} ` + + `can only be used in render() or setup().`); + } +} +function resolve(registry, name) { + return (registry && + (registry[name] || + registry[camelize(name)] || + registry[capitalize(camelize(name))])); +} + +const Fragment = Symbol((process.env.NODE_ENV !== 'production') ? 'Fragment' : undefined); +const Text = Symbol((process.env.NODE_ENV !== 'production') ? 'Text' : undefined); +const Comment = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : undefined); +const Static = Symbol((process.env.NODE_ENV !== 'production') ? 'Static' : undefined); +// Since v-if and v-for are the two possible ways node structure can dynamically +// change, once we consider v-if branches and each v-for fragment a block, we +// can divide a template into nested blocks, and within each block the node +// structure would be stable. This allows us to skip most children diffing +// and only worry about the dynamic nodes (indicated by patch flags). +const blockStack = []; +let currentBlock = null; +/** + * Open a block. + * This must be called before `createBlock`. It cannot be part of `createBlock` + * because the children of the block are evaluated before `createBlock` itself + * is called. The generated code typically looks like this: + * + * ```js + * function render() { + * return (openBlock(),createBlock('div', null, [...])) + * } + * ``` + * disableTracking is true when creating a v-for fragment block, since a v-for + * fragment always diffs its children. + * + * @private + */ +function openBlock(disableTracking = false) { + blockStack.push((currentBlock = disableTracking ? null : [])); +} +function closeBlock() { + blockStack.pop(); + currentBlock = blockStack[blockStack.length - 1] || null; +} +// Whether we should be tracking dynamic child nodes inside a block. +// Only tracks when this value is > 0 +// We are not using a simple boolean because this value may need to be +// incremented/decremented by nested usage of v-once (see below) +let shouldTrack$1 = 1; +/** + * Block tracking sometimes needs to be disabled, for example during the + * creation of a tree that needs to be cached by v-once. The compiler generates + * code like this: + * + * ``` js + * _cache[1] || ( + * setBlockTracking(-1), + * _cache[1] = createVNode(...), + * setBlockTracking(1), + * _cache[1] + * ) + * ``` + * + * @private + */ +function setBlockTracking(value) { + shouldTrack$1 += value; +} +/** + * Create a block root vnode. Takes the same exact arguments as `createVNode`. + * A block root keeps track of dynamic nodes within the block in the + * `dynamicChildren` array. + * + * @private + */ +function createBlock(type, props, children, patchFlag, dynamicProps) { + const vnode = createVNode(type, props, children, patchFlag, dynamicProps, true /* isBlock: prevent a block from tracking itself */); + // save current block children on the block vnode + vnode.dynamicChildren = currentBlock || EMPTY_ARR; + // close block + closeBlock(); + // a block is always going to be patched, so track it as a child of its + // parent block + if (shouldTrack$1 > 0 && currentBlock) { + currentBlock.push(vnode); + } + return vnode; +} +function isVNode(value) { + return value ? value.__v_isVNode === true : false; +} +function isSameVNodeType(n1, n2) { + if ((process.env.NODE_ENV !== 'production') && + n2.shapeFlag & 6 /* COMPONENT */ && + hmrDirtyComponents.has(n2.type)) { + // HMR only: if the component has been hot-updated, force a reload. + return false; + } + return n1.type === n2.type && n1.key === n2.key; +} +let vnodeArgsTransformer; +/** + * Internal API for registering an arguments transform for createVNode + * used for creating stubs in the test-utils + * It is *internal* but needs to be exposed for test-utils to pick up proper + * typings + */ +function transformVNodeArgs(transformer) { + vnodeArgsTransformer = transformer; +} +const createVNodeWithArgsTransform = (...args) => { + return _createVNode(...(vnodeArgsTransformer + ? vnodeArgsTransformer(args, currentRenderingInstance) + : args)); +}; +const InternalObjectKey = `__vInternal`; +const normalizeKey = ({ key }) => key != null ? key : null; +const normalizeRef = ({ ref }) => { + return (ref != null + ? isArray(ref) + ? ref + : { i: currentRenderingInstance, r: ref } + : null); +}; +const createVNode = ((process.env.NODE_ENV !== 'production') + ? createVNodeWithArgsTransform + : _createVNode); +function _createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, isBlockNode = false) { + if (!type || type === NULL_DYNAMIC_COMPONENT) { + if ((process.env.NODE_ENV !== 'production') && !type) { + warn(`Invalid vnode type when creating vnode: ${type}.`); + } + type = Comment; + } + if (isVNode(type)) { + // createVNode receiving an existing vnode. This happens in cases like + // + // #2078 make sure to merge refs during the clone instead of overwriting it + const cloned = cloneVNode(type, props, true /* mergeRef: true */); + if (children) { + normalizeChildren(cloned, children); + } + return cloned; + } + // class component normalization. + if (isClassComponent(type)) { + type = type.__vccOpts; + } + // class & style normalization. + if (props) { + // for reactive or proxy objects, we need to clone it to enable mutation. + if (isProxy(props) || InternalObjectKey in props) { + props = extend({}, props); + } + let { class: klass, style } = props; + if (klass && !isString(klass)) { + props.class = normalizeClass(klass); + } + if (isObject(style)) { + // reactive state objects need to be cloned since they are likely to be + // mutated + if (isProxy(style) && !isArray(style)) { + style = extend({}, style); + } + props.style = normalizeStyle(style); + } + } + // encode the vnode type information into a bitmap + const shapeFlag = isString(type) + ? 1 /* ELEMENT */ + : isSuspense(type) + ? 128 /* SUSPENSE */ + : isTeleport(type) + ? 64 /* TELEPORT */ + : isObject(type) + ? 4 /* STATEFUL_COMPONENT */ + : isFunction(type) + ? 2 /* FUNCTIONAL_COMPONENT */ + : 0; + if ((process.env.NODE_ENV !== 'production') && shapeFlag & 4 /* STATEFUL_COMPONENT */ && isProxy(type)) { + type = toRaw(type); + warn(`Vue received a Component which was made a reactive object. This can ` + + `lead to unnecessary performance overhead, and should be avoided by ` + + `marking the component with \`markRaw\` or using \`shallowRef\` ` + + `instead of \`ref\`.`, `\nComponent that was made reactive: `, type); + } + const vnode = { + __v_isVNode: true, + ["__v_skip" /* SKIP */]: true, + type, + props, + key: props && normalizeKey(props), + ref: props && normalizeRef(props), + scopeId: currentScopeId, + children: null, + component: null, + suspense: null, + ssContent: null, + ssFallback: null, + dirs: null, + transition: null, + el: null, + anchor: null, + target: null, + targetAnchor: null, + staticCount: 0, + shapeFlag, + patchFlag, + dynamicProps, + dynamicChildren: null, + appContext: null + }; + // validate key + if ((process.env.NODE_ENV !== 'production') && vnode.key !== vnode.key) { + warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type); + } + normalizeChildren(vnode, children); + // normalize suspense children + if ( shapeFlag & 128 /* SUSPENSE */) { + const { content, fallback } = normalizeSuspenseChildren(vnode); + vnode.ssContent = content; + vnode.ssFallback = fallback; + } + if (shouldTrack$1 > 0 && + // avoid a block node from tracking itself + !isBlockNode && + // has current parent block + currentBlock && + // presence of a patch flag indicates this node needs patching on updates. + // component nodes also should always be patched, because even if the + // component doesn't need to update, it needs to persist the instance on to + // the next vnode so that it can be properly unmounted later. + (patchFlag > 0 || shapeFlag & 6 /* COMPONENT */) && + // the EVENTS flag is only for hydration and if it is the only flag, the + // vnode should not be considered dynamic due to handler caching. + patchFlag !== 32 /* HYDRATE_EVENTS */) { + currentBlock.push(vnode); + } + return vnode; +} +function cloneVNode(vnode, extraProps, mergeRef = false) { + // This is intentionally NOT using spread or extend to avoid the runtime + // key enumeration cost. + const { props, ref, patchFlag } = vnode; + const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props; + return { + __v_isVNode: true, + ["__v_skip" /* SKIP */]: true, + type: vnode.type, + props: mergedProps, + key: mergedProps && normalizeKey(mergedProps), + ref: extraProps && extraProps.ref + ? // #2078 in the case of + // if the vnode itself already has a ref, cloneVNode will need to merge + // the refs so the single vnode can be set on multiple refs + mergeRef && ref + ? isArray(ref) + ? ref.concat(normalizeRef(extraProps)) + : [ref, normalizeRef(extraProps)] + : normalizeRef(extraProps) + : ref, + scopeId: vnode.scopeId, + children: vnode.children, + target: vnode.target, + targetAnchor: vnode.targetAnchor, + staticCount: vnode.staticCount, + shapeFlag: vnode.shapeFlag, + // if the vnode is cloned with extra props, we can no longer assume its + // existing patch flag to be reliable and need to add the FULL_PROPS flag. + // note: perserve flag for fragments since they use the flag for children + // fast paths only. + patchFlag: extraProps && vnode.type !== Fragment + ? patchFlag === -1 // hoisted node + ? 16 /* FULL_PROPS */ + : patchFlag | 16 /* FULL_PROPS */ + : patchFlag, + dynamicProps: vnode.dynamicProps, + dynamicChildren: vnode.dynamicChildren, + appContext: vnode.appContext, + dirs: vnode.dirs, + transition: vnode.transition, + // These should technically only be non-null on mounted VNodes. However, + // they *should* be copied for kept-alive vnodes. So we just always copy + // them since them being non-null during a mount doesn't affect the logic as + // they will simply be overwritten. + component: vnode.component, + suspense: vnode.suspense, + ssContent: vnode.ssContent && cloneVNode(vnode.ssContent), + ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback), + el: vnode.el, + anchor: vnode.anchor + }; +} +/** + * @private + */ +function createTextVNode(text = ' ', flag = 0) { + return createVNode(Text, null, text, flag); +} +/** + * @private + */ +function createStaticVNode(content, numberOfNodes) { + // A static vnode can contain multiple stringified elements, and the number + // of elements is necessary for hydration. + const vnode = createVNode(Static, null, content); + vnode.staticCount = numberOfNodes; + return vnode; +} +/** + * @private + */ +function createCommentVNode(text = '', +// when used as the v-else branch, the comment node must be created as a +// block to ensure correct updates. +asBlock = false) { + return asBlock + ? (openBlock(), createBlock(Comment, null, text)) + : createVNode(Comment, null, text); +} +function normalizeVNode(child) { + if (child == null || typeof child === 'boolean') { + // empty placeholder + return createVNode(Comment); + } + else if (isArray(child)) { + // fragment + return createVNode(Fragment, null, child); + } + else if (typeof child === 'object') { + // already vnode, this should be the most common since compiled templates + // always produce all-vnode children arrays + return child.el === null ? child : cloneVNode(child); + } else { - getter = NOOP; - (process.env.NODE_ENV !== 'production') && warnInvalidSource(source); + // strings and numbers + return createVNode(Text, null, String(child)); } - if (cb && deep) { - const baseGetter = getter; - getter = () => traverse(baseGetter()); +} +// optimized normalization for template-compiled render fns +function cloneIfMounted(child) { + return child.el === null ? child : cloneVNode(child); +} +function normalizeChildren(vnode, children) { + let type = 0; + const { shapeFlag } = vnode; + if (children == null) { + children = null; } - let cleanup; - const onInvalidate = (fn) => { - cleanup = runner.options.onStop = () => { - callWithErrorHandling(fn, instance, 4 /* WATCH_CLEANUP */); - }; - }; - let oldValue = isArray(source) ? [] : INITIAL_WATCHER_VALUE; - const job = () => { - if (!runner.active) { + else if (isArray(children)) { + type = 16 /* ARRAY_CHILDREN */; + } + else if (typeof children === 'object') { + if (shapeFlag & 1 /* ELEMENT */ || shapeFlag & 64 /* TELEPORT */) { + // Normalize slot to plain children for plain element and Teleport + const slot = children.default; + if (slot) { + // _c marker is added by withCtx() indicating this is a compiled slot + slot._c && setCompiledSlotRendering(1); + normalizeChildren(vnode, slot()); + slot._c && setCompiledSlotRendering(-1); + } return; } - if (cb) { - // watch(source, cb) - const newValue = runner(); - if (deep || isRefSource || hasChanged(newValue, oldValue)) { - // cleanup before running cb again - if (cleanup) { - cleanup(); + else { + type = 32 /* SLOTS_CHILDREN */; + const slotFlag = children._; + if (!slotFlag && !(InternalObjectKey in children)) { + children._ctx = currentRenderingInstance; + } + else if (slotFlag === 3 /* FORWARDED */ && currentRenderingInstance) { + // a child component receives forwarded slots from the parent. + // its slot type is determined by its parent's slot type. + if (currentRenderingInstance.vnode.patchFlag & 1024 /* DYNAMIC_SLOTS */) { + children._ = 2 /* DYNAMIC */; + vnode.patchFlag |= 1024 /* DYNAMIC_SLOTS */; + } + else { + children._ = 1 /* STABLE */; } - callWithAsyncErrorHandling(cb, instance, 3 /* WATCH_CALLBACK */, [ - newValue, - // pass undefined as the old value when it's changed for the first time - oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue, - onInvalidate - ]); - oldValue = newValue; } } - else { - // watchEffect - runner(); - } - }; - // important: mark the job as a watcher callback so that scheduler knows it - // it is allowed to self-trigger (#1727) - job.allowRecurse = !!cb; - let scheduler; - if (flush === 'sync') { - scheduler = job; } - else if (flush === 'post') { - scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); + else if (isFunction(children)) { + children = { default: children, _ctx: currentRenderingInstance }; + type = 32 /* SLOTS_CHILDREN */; } else { - // default: 'pre' - scheduler = () => { - if (!instance || instance.isMounted) { - queuePreFlushCb(job); - } - else { - // with 'pre' option, the first call must happen before - // the component is mounted so it is called synchronously. - job(); - } - }; - } - const runner = effect(getter, { - lazy: true, - onTrack, - onTrigger, - scheduler - }); - recordInstanceBoundEffect(runner); - // initial run - if (cb) { - if (immediate) { - job(); + children = String(children); + // force teleport children to array so it can be moved around + if (shapeFlag & 64 /* TELEPORT */) { + type = 16 /* ARRAY_CHILDREN */; + children = [createTextVNode(children)]; } else { - oldValue = runner(); + type = 8 /* TEXT_CHILDREN */; } } - else if (flush === 'post') { - queuePostRenderEffect(runner, instance && instance.suspense); - } - else { - runner(); - } - return () => { - stop(runner); - if (instance) { - remove(instance.effects, runner); - } - }; -} -// this.$watch -function instanceWatch(source, cb, options) { - const publicThis = this.proxy; - const getter = isString(source) - ? () => publicThis[source] - : source.bind(publicThis); - return doWatch(getter, cb.bind(publicThis), options, this); + vnode.children = children; + vnode.shapeFlag |= type; } -function traverse(value, seen = new Set()) { - if (!isObject(value) || seen.has(value)) { - return value; - } - seen.add(value); - if (isRef(value)) { - traverse(value.value, seen); - } - else if (isArray(value)) { - for (let i = 0; i < value.length; i++) { - traverse(value[i], seen); - } - } - else if (isMap(value)) { - value.forEach((_, key) => { - // to register mutation dep for existing keys - traverse(value.get(key), seen); - }); - } - else if (isSet(value)) { - value.forEach(v => { - traverse(v, seen); - }); - } - else { - for (const key in value) { - traverse(value[key], seen); +function mergeProps(...args) { + const ret = extend({}, args[0]); + for (let i = 1; i < args.length; i++) { + const toMerge = args[i]; + for (const key in toMerge) { + if (key === 'class') { + if (ret.class !== toMerge.class) { + ret.class = normalizeClass([ret.class, toMerge.class]); + } + } + else if (key === 'style') { + ret.style = normalizeStyle([ret.style, toMerge.style]); + } + else if (isOn(key)) { + const existing = ret[key]; + const incoming = toMerge[key]; + if (existing !== incoming) { + ret[key] = existing + ? [].concat(existing, toMerge[key]) + : incoming; + } + } + else if (key !== '') { + ret[key] = toMerge[key]; + } } } - return value; + return ret; } function provide(key, value) { @@ -6256,8 +6275,13 @@ function inject(key, defaultValue, treatDefaultAsFactory = false) { // a functional component const instance = currentInstance || currentRenderingInstance; if (instance) { - const provides = instance.provides; - if (key in provides) { + // #2400 + // to support `app.use` plugins, + // fallback to appContext's `provides` if the intance is at root + const provides = instance.parent == null + ? instance.vnode.appContext && instance.vnode.appContext.provides + : instance.parent.provides; + if (provides && key in provides) { // TS doesn't allow symbol as index type return provides[key]; } @@ -6287,7 +6311,7 @@ function createDuplicateChecker() { }; } let isInBeforeCreate = false; -function applyOptions(instance, options, deferredData = [], deferredWatch = [], asMixin = false) { +function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) { const { // composition mixins, extends: extendsOptions, @@ -6306,18 +6330,18 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], // applyOptions is called non-as-mixin once per instance if (!asMixin) { isInBeforeCreate = true; - callSyncHook('beforeCreate', options, publicThis, globalMixins); + callSyncHook('beforeCreate', "bc" /* BEFORE_CREATE */, options, instance, globalMixins); isInBeforeCreate = false; // global mixins are applied first - applyMixins(instance, globalMixins, deferredData, deferredWatch); + applyMixins(instance, globalMixins, deferredData, deferredWatch, deferredProvide); } // extending a base component... if (extendsOptions) { - applyOptions(instance, extendsOptions, deferredData, deferredWatch, true); + applyOptions(instance, extendsOptions, deferredData, deferredWatch, deferredProvide, true); } // local mixins if (mixins) { - applyMixins(instance, mixins, deferredData, deferredWatch); + applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide); } const checkDuplicateProperties = (process.env.NODE_ENV !== 'production') ? createDuplicateChecker() : null; if ((process.env.NODE_ENV !== 'production')) { @@ -6445,12 +6469,17 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], }); } if (provideOptions) { - const provides = isFunction(provideOptions) - ? provideOptions.call(publicThis) - : provideOptions; - for (const key in provides) { - provide(key, provides[key]); - } + deferredProvide.push(provideOptions); + } + if (!asMixin && deferredProvide.length) { + deferredProvide.forEach(provideOptions => { + const provides = isFunction(provideOptions) + ? provideOptions.call(publicThis) + : provideOptions; + for (const key in provides) { + provide(key, provides[key]); + } + }); } // asset options. // To reduce memory usage, only components with mixins or extends will have @@ -6467,7 +6496,7 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } // lifecycle options if (!asMixin) { - callSyncHook('created', options, publicThis, globalMixins); + callSyncHook('created', "c" /* CREATED */, options, instance, globalMixins); } if (beforeMount) { onBeforeMount(beforeMount.bind(publicThis)); @@ -6509,44 +6538,44 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], onUnmounted(unmounted.bind(publicThis)); } } -function callSyncHook(name, options, ctx, globalMixins) { - callHookFromMixins(name, globalMixins, ctx); +function callSyncHook(name, type, options, instance, globalMixins) { + callHookFromMixins(name, type, globalMixins, instance); const { extends: base, mixins } = options; if (base) { - callHookFromExtends(name, base, ctx); + callHookFromExtends(name, type, base, instance); } if (mixins) { - callHookFromMixins(name, mixins, ctx); + callHookFromMixins(name, type, mixins, instance); } const selfHook = options[name]; if (selfHook) { - selfHook.call(ctx); + callWithAsyncErrorHandling(selfHook.bind(instance.proxy), instance, type); } } -function callHookFromExtends(name, base, ctx) { +function callHookFromExtends(name, type, base, instance) { if (base.extends) { - callHookFromExtends(name, base.extends, ctx); + callHookFromExtends(name, type, base.extends, instance); } const baseHook = base[name]; if (baseHook) { - baseHook.call(ctx); + callWithAsyncErrorHandling(baseHook.bind(instance.proxy), instance, type); } } -function callHookFromMixins(name, mixins, ctx) { +function callHookFromMixins(name, type, mixins, instance) { for (let i = 0; i < mixins.length; i++) { const chainedMixins = mixins[i].mixins; if (chainedMixins) { - callHookFromMixins(name, chainedMixins, ctx); + callHookFromMixins(name, type, chainedMixins, instance); } const fn = mixins[i][name]; if (fn) { - fn.call(ctx); + callWithAsyncErrorHandling(fn.bind(instance.proxy), instance, type); } } } -function applyMixins(instance, mixins, deferredData, deferredWatch) { +function applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide) { for (let i = 0; i < mixins.length; i++) { - applyOptions(instance, mixins[i], deferredData, deferredWatch, true); + applyOptions(instance, mixins[i], deferredData, deferredWatch, deferredProvide, true); } } function resolveData(instance, dataFn, publicThis) { @@ -6659,7 +6688,7 @@ const publicPropertiesMap = extend(Object.create(null), { $emit: i => i.emit, $options: i => (__VUE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type), $forceUpdate: i => () => queueJob(i.update), - $nextTick: () => nextTick, + $nextTick: i => nextTick.bind(i.proxy), $watch: i => (__VUE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP) }); const PublicInstanceProxyHandlers = { @@ -6669,6 +6698,10 @@ const PublicInstanceProxyHandlers = { if (key === "__v_skip" /* SKIP */) { return true; } + // for internal formatters to know that this is a Vue instance + if ((process.env.NODE_ENV !== 'production') && key === '__isVue') { + return true; + } // data / props / ctx // This getter gets called for every property access on the render context // during render and is a major hotspot. The most expensive part of this @@ -7016,7 +7049,7 @@ function setupStatefulComponent(instance, isSSR) { } } // 0. create render proxy property access cache - instance.accessCache = {}; + instance.accessCache = Object.create(null); // 1. create public instance / render proxy // also mark it raw so it's never observed instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers); @@ -7387,6 +7420,195 @@ const useSSRContext = () => { } }; +function initCustomFormatter() { + if (!(process.env.NODE_ENV !== 'production') || !true) { + return; + } + const vueStyle = { style: 'color:#3ba776' }; + const numberStyle = { style: 'color:#0b1bc9' }; + const stringStyle = { style: 'color:#b62e24' }; + const keywordStyle = { style: 'color:#9d288c' }; + // custom formatter for Chrome + // https://www.mattzeunert.com/2016/02/19/custom-chrome-devtools-object-formatters.html + const formatter = { + header(obj) { + // TODO also format ComponentPublicInstance & ctx.slots/attrs in setup + if (!isObject(obj)) { + return null; + } + if (obj.__isVue) { + return ['div', vueStyle, `VueInstance`]; + } + else if (isRef(obj)) { + return [ + 'div', + {}, + ['span', vueStyle, genRefFlag(obj)], + '<', + formatValue(obj.value), + `>` + ]; + } + else if (isReactive(obj)) { + return [ + 'div', + {}, + ['span', vueStyle, 'Reactive'], + '<', + formatValue(obj), + `>${isReadonly(obj) ? ` (readonly)` : ``}` + ]; + } + else if (isReadonly(obj)) { + return [ + 'div', + {}, + ['span', vueStyle, 'Readonly'], + '<', + formatValue(obj), + '>' + ]; + } + return null; + }, + hasBody(obj) { + return obj && obj.__isVue; + }, + body(obj) { + if (obj && obj.__isVue) { + return [ + 'div', + {}, + ...formatInstance(obj.$) + ]; + } + } + }; + function formatInstance(instance) { + const blocks = []; + if (instance.type.props && instance.props) { + blocks.push(createInstanceBlock('props', toRaw(instance.props))); + } + if (instance.setupState !== EMPTY_OBJ) { + blocks.push(createInstanceBlock('setup', instance.setupState)); + } + if (instance.data !== EMPTY_OBJ) { + blocks.push(createInstanceBlock('data', toRaw(instance.data))); + } + const computed = extractKeys(instance, 'computed'); + if (computed) { + blocks.push(createInstanceBlock('computed', computed)); + } + const injected = extractKeys(instance, 'inject'); + if (injected) { + blocks.push(createInstanceBlock('injected', injected)); + } + blocks.push([ + 'div', + {}, + [ + 'span', + { + style: keywordStyle.style + ';opacity:0.66' + }, + '$ (internal): ' + ], + ['object', { object: instance }] + ]); + return blocks; + } + function createInstanceBlock(type, target) { + target = extend({}, target); + if (!Object.keys(target).length) { + return ['span', {}]; + } + return [ + 'div', + { style: 'line-height:1.25em;margin-bottom:0.6em' }, + [ + 'div', + { + style: 'color:#476582' + }, + type + ], + [ + 'div', + { + style: 'padding-left:1.25em' + }, + ...Object.keys(target).map(key => { + return [ + 'div', + {}, + ['span', keywordStyle, key + ': '], + formatValue(target[key], false) + ]; + }) + ] + ]; + } + function formatValue(v, asRaw = true) { + if (typeof v === 'number') { + return ['span', numberStyle, v]; + } + else if (typeof v === 'string') { + return ['span', stringStyle, JSON.stringify(v)]; + } + else if (typeof v === 'boolean') { + return ['span', keywordStyle, v]; + } + else if (isObject(v)) { + return ['object', { object: asRaw ? toRaw(v) : v }]; + } + else { + return ['span', stringStyle, String(v)]; + } + } + function extractKeys(instance, type) { + const Comp = instance.type; + if (isFunction(Comp)) { + return; + } + const extracted = {}; + for (const key in instance.ctx) { + if (isKeyOfType(Comp, key, type)) { + extracted[key] = instance.ctx[key]; + } + } + return extracted; + } + function isKeyOfType(Comp, key, type) { + const opts = Comp[type]; + if ((isArray(opts) && opts.includes(key)) || + (isObject(opts) && key in opts)) { + return true; + } + if (Comp.extends && isKeyOfType(Comp.extends, key, type)) { + return true; + } + if (Comp.mixins && Comp.mixins.some(m => isKeyOfType(m, key, type))) { + return true; + } + } + function genRefFlag(v) { + if (v._shallow) { + return `ShallowRef`; + } + if (v.effect) { + return `ComputedRef`; + } + return `Ref`; + } + /* eslint-disable no-restricted-globals */ + if (window.devtoolsFormatters) { + window.devtoolsFormatters.push(formatter); + } + else { + window.devtoolsFormatters = [formatter]; + } +} + /** * Actual implementation */ @@ -7399,6 +7621,10 @@ function renderList(source, renderItem) { } } else if (typeof source === 'number') { + if ((process.env.NODE_ENV !== 'production') && !Number.isInteger(source)) { + warn(`The v-for range expect an integer value but got ${source}.`); + return []; + } ret = new Array(source); for (let i = 0; i < source; i++) { ret[i] = renderItem(i + 1, i); @@ -7434,7 +7660,7 @@ function toHandlers(obj) { return ret; } for (const key in obj) { - ret[`on${capitalize(key)}`] = obj[key]; + ret[toHandlerKey(key)] = obj[key]; } return ret; } @@ -7461,7 +7687,7 @@ function createSlots(slots, dynamicSlots) { } // Core API ------------------------------------------------------------------ -const version = "3.0.0"; +const version = "3.0.2"; /** * SSR utils for \@vue/server-renderer. Only exposed in cjs builds. * @internal @@ -7885,11 +8111,9 @@ function useCssVars(getter, scoped = false) { const prefix = scoped && instance.type.__scopeId ? `${instance.type.__scopeId.replace(/^data-v-/, '')}-` : ``; - onMounted(() => { - watchEffect(() => { - setVarsOnVNode(instance.subTree, getter(instance.proxy), prefix); - }); - }); + const setVars = () => setVarsOnVNode(instance.subTree, getter(instance.proxy), prefix); + onMounted(() => watchEffect(setVars)); + onUpdated(setVars); } function setVarsOnVNode(vnode, vars, prefix) { if ( vnode.shapeFlag & 128 /* SUSPENSE */) { @@ -8315,8 +8539,7 @@ function trigger$1(el, type) { // We are exporting the v-model runtime directly as vnode hooks so that it can // be tree-shaken in case v-model is never used. const vModelText = { - created(el, { value, modifiers: { lazy, trim, number } }, vnode) { - el.value = value == null ? '' : value; + created(el, { modifiers: { lazy, trim, number } }, vnode) { el._assign = getModelAssigner(vnode); const castToNumber = number || el.type === 'number'; addEventListener(el, lazy ? 'change' : 'input', e => { @@ -8346,8 +8569,15 @@ const vModelText = { addEventListener(el, 'change', onCompositionEnd); } }, + // set value on mounted so it's after min/max for type="range" + mounted(el, { value }) { + el.value = value == null ? '' : value; + }, beforeUpdate(el, { value, modifiers: { trim, number } }, vnode) { el._assign = getModelAssigner(vnode); + // avoid clearing unresolved text. #2302 + if (el.composing) + return; if (document.activeElement === el) { if (trim && el.value.trim() === value) { return; @@ -8384,13 +8614,11 @@ const vModelCheckbox = { } } else if (isSet(modelValue)) { - const found = modelValue.has(elementValue); - if (checked && !found) { - assign(modelValue.add(elementValue)); + if (checked) { + modelValue.add(elementValue); } - else if (!checked && found) { + else { modelValue.delete(elementValue); - assign(modelValue); } } else { @@ -8409,7 +8637,7 @@ function setChecked(el, { value, oldValue }, vnode) { el.checked = looseIndexOf(value, vnode.props.value) > -1; } else if (isSet(value)) { - el.checked = looseHas(value, vnode.props.value); + el.checked = value.has(vnode.props.value); } else if (value !== oldValue) { el.checked = looseEqual(value, getCheckboxValue(el, true)); @@ -8431,11 +8659,11 @@ const vModelRadio = { } }; const vModelSelect = { - created(el, binding, vnode) { + created(el, { modifiers: { number } }, vnode) { addEventListener(el, 'change', () => { const selectedVal = Array.prototype.filter .call(el.options, (o) => o.selected) - .map(getValue); + .map((o) => number ? toNumber(getValue(o)) : getValue(o)); el._assign(el.multiple ? selectedVal : selectedVal[0]); }); el._assign = getModelAssigner(vnode); @@ -8468,7 +8696,7 @@ function setSelected(el, value) { option.selected = looseIndexOf(value, optionValue) > -1; } else { - option.selected = looseHas(value, optionValue); + option.selected = value.has(optionValue); } } else { @@ -8712,6 +8940,7 @@ function initDev() { { console.info(`You are running a development build of Vue.\n` + `Make sure to use the production build (*.prod.js) when deploying for production.`); + initCustomFormatter(); } } @@ -8754,4 +8983,4 @@ const onNavigationBarSearchInputClicked = /*#__PURE__*/ createHook$1("onNavigati const onNavigationBarSearchInputConfirmed = /*#__PURE__*/ createHook$1("onNavigationBarSearchInputConfirmed" /* ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED */); const onNavigationBarSearchInputFocusChanged = /*#__PURE__*/ createHook$1("onNavigationBarSearchInputFocusChanged" /* ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED */); -export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHook$1 as createHook, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, customRef, defineAsyncComponent, defineComponent, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isVNode, markRaw, mergeProps, nextTick, onActivated, onAddToFavorites, onBackPress, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onError, onErrorCaptured, onHide, onLaunch, onLoad, onMounted, onNavigationBarButtonTap, onNavigationBarSearchInputChanged, onNavigationBarSearchInputClicked, onNavigationBarSearchInputConfirmed, onNavigationBarSearchInputFocusChanged, onPageNotFound, onPageScroll, onPullDownRefresh, onReachBottom, onReady, onRenderTracked, onRenderTriggered, onResize, onShareAppMessage, onShareTimeline, onShow, onTabItemTap, onThemeChange, onUnhandledRejection, onUnload, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId }; +export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHook$1 as createHook, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, customRef, defineAsyncComponent, defineComponent, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isVNode, markRaw, mergeProps, nextTick, onActivated, onAddToFavorites, onBackPress, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onError, onErrorCaptured, onHide, onLaunch, onLoad, onMounted, onNavigationBarButtonTap, onNavigationBarSearchInputChanged, onNavigationBarSearchInputClicked, onNavigationBarSearchInputConfirmed, onNavigationBarSearchInputFocusChanged, onPageNotFound, onPageScroll, onPullDownRefresh, onReachBottom, onReady, onRenderTracked, onRenderTriggered, onResize, onShareAppMessage, onShareTimeline, onShow, onTabItemTap, onThemeChange, onUnhandledRejection, onUnload, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId }; diff --git a/packages/uni-h5-vue/lib/vue.runtime.esm.js b/packages/uni-h5-vue/lib/vue.runtime.esm.js index 0b5994187..3c12353a5 100644 --- a/packages/uni-h5-vue/lib/vue.runtime.esm.js +++ b/packages/uni-h5-vue/lib/vue.runtime.esm.js @@ -1,5 +1,5 @@ -import { EMPTY_OBJ, isArray, isMap, isIntegerKey, isSymbol, extend, hasOwn, isObject, hasChanged, capitalize, toRawType, def, isFunction, NOOP, isString, isPromise, hyphenate, isOn, isModelListener, toNumber, camelize, EMPTY_ARR, normalizeClass, normalizeStyle, isReservedProp, makeMap, remove, invokeArrayFns, NO, getGlobalThis, isSet, isGloballyWhitelisted, isSpecialBooleanAttr, looseIndexOf, looseHas, looseEqual, isHTMLTag, isSVGTag } from '@vue/shared'; -export { camelize, capitalize, toDisplayString } from '@vue/shared'; +import { EMPTY_OBJ, isArray, isMap, isIntegerKey, isSymbol, extend, hasOwn, isObject, hasChanged, capitalize, toRawType, def, isFunction, NOOP, isString, isPromise, toHandlerKey, toNumber, hyphenate, camelize, isOn, isModelListener, isReservedProp, EMPTY_ARR, makeMap, remove, isSet, invokeArrayFns, NO, getGlobalThis, normalizeClass, normalizeStyle, isGloballyWhitelisted, isSpecialBooleanAttr, looseIndexOf, looseEqual, isHTMLTag, isSVGTag } from '@vue/shared'; +export { camelize, capitalize, toDisplayString, toHandlerKey } from '@vue/shared'; const targetMap = new WeakMap(); const effectStack = []; @@ -50,6 +50,7 @@ function createReactiveEffect(fn, options) { } }; effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; effect._isEffect = true; effect.active = true; effect.raw = fn; @@ -115,7 +116,7 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) { const add = (effectsToAdd) => { if (effectsToAdd) { effectsToAdd.forEach(effect => { - if (effect !== activeEffect || effect.options.allowRecurse) { + if (effect !== activeEffect || effect.allowRecurse) { effects.add(effect); } }); @@ -220,7 +221,7 @@ const arrayInstrumentations = {}; arrayInstrumentations[key] = function (...args) { pauseTracking(); const res = method.apply(this, args); - enableTracking(); + resetTracking(); return res; }; }); @@ -241,8 +242,7 @@ function createGetter(isReadonly = false, shallow = false) { return Reflect.get(arrayInstrumentations, key, receiver); } const res = Reflect.get(target, key, receiver); - const keyIsSymbol = isSymbol(key); - if (keyIsSymbol + if (isSymbol(key) ? builtInSymbols.has(key) : key === `__proto__` || key === `__v_isRef`) { return res; @@ -312,7 +312,7 @@ function has(target, key) { return result; } function ownKeys(target) { - track(target, "iterate" /* ITERATE */, ITERATE_KEY); + track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY); return Reflect.ownKeys(target); } const mutableHandlers = { @@ -595,7 +595,7 @@ function checkIdentityKeys(target, has, key) { if (rawKey !== key && has.call(target, rawKey)) { const type = toRawType(target); console.warn(`Reactive ${type} contains both the raw and reactive ` + - `versions of the same object${type === `Map` ? `as keys` : ``}, ` + + `versions of the same object${type === `Map` ? ` as keys` : ``}, ` + `which can lead to inconsistencies. ` + `Avoid differentiating between the raw and reactive versions ` + `of an object and only use the reactive version if possible.`); @@ -730,7 +730,7 @@ function createRef(rawValue, shallow = false) { return new RefImpl(rawValue, shallow); } function triggerRef(ref) { - trigger(ref, "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); + trigger(toRaw(ref), "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); } function unref(ref) { return isRef(ref) ? ref.value : ref; @@ -1028,7 +1028,7 @@ function handleError(err, instance, type, throwInDev = true) { const errorCapturedHooks = cur.ec; if (errorCapturedHooks) { for (let i = 0; i < errorCapturedHooks.length; i++) { - if (errorCapturedHooks[i](err, exposedInstance, errorInfo)) { + if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) { return; } } @@ -1084,7 +1084,7 @@ let currentPreFlushParentJob = null; const RECURSION_LIMIT = 100; function nextTick(fn) { const p = currentFlushPromise || resolvedPromise; - return fn ? p.then(fn) : p; + return fn ? p.then(this ? fn.bind(this) : fn) : p; } function queueJob(job) { // the dedupe search uses the startIndex argument of Array.includes() @@ -1247,7 +1247,7 @@ const hmrDirtyComponents = new Set(); // it easier to be used in toolings like vue-loader // Note: for a component to be eligible for HMR it also needs the __hmrId option // to be set so that its instances can be registered / removed. -if ((process.env.NODE_ENV !== 'production')) { +if ((process.env.NODE_ENV !== 'production') && (true )) { const globalObject = typeof global !== 'undefined' ? global : typeof self !== 'undefined' @@ -1391,21 +1391,21 @@ function devtoolsComponentEmit(component, event, params) { devtools.emit("component:emit" /* COMPONENT_EMIT */, component.appContext.app, component, event, params); } -function emit(instance, event, ...args) { +function emit(instance, event, ...rawArgs) { const props = instance.vnode.props || EMPTY_OBJ; if ((process.env.NODE_ENV !== 'production')) { const { emitsOptions, propsOptions: [propsOptions] } = instance; if (emitsOptions) { if (!(event in emitsOptions)) { - if (!propsOptions || !(`on` + capitalize(event) in propsOptions)) { + if (!propsOptions || !(toHandlerKey(event) in propsOptions)) { warn(`Component emitted event "${event}" but it is neither declared in ` + - `the emits option nor as an "on${capitalize(event)}" prop.`); + `the emits option nor as an "${toHandlerKey(event)}" prop.`); } } else { const validator = emitsOptions[event]; if (isFunction(validator)) { - const isValid = validator(...args); + const isValid = validator(...rawArgs); if (!isValid) { warn(`Invalid event arguments: event validation failed for event "${event}".`); } @@ -1413,36 +1413,59 @@ function emit(instance, event, ...args) { } } } + let args = rawArgs; + const isModelListener = event.startsWith('update:'); + // for v-model update:xxx events, apply modifiers on args + const modelArg = isModelListener && event.slice(7); + if (modelArg && modelArg in props) { + const modifiersKey = `${modelArg === 'modelValue' ? 'model' : modelArg}Modifiers`; + const { number, trim } = props[modifiersKey] || EMPTY_OBJ; + if (trim) { + args = rawArgs.map(a => a.trim()); + } + else if (number) { + args = rawArgs.map(toNumber); + } + } if ((process.env.NODE_ENV !== 'production') || __VUE_PROD_DEVTOOLS__) { devtoolsComponentEmit(instance, event, args); } - let handlerName = `on${capitalize(event)}`; + if ((process.env.NODE_ENV !== 'production')) { + const lowerCaseEvent = event.toLowerCase(); + if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) { + warn(`Event "${lowerCaseEvent}" is emitted in component ` + + `${formatComponentName(instance, instance.type)} but the handler is registered for "${event}". ` + + `Note that HTML attributes are case-insensitive and you cannot use ` + + `v-on to listen to camelCase events when using in-DOM templates. ` + + `You should probably use "${hyphenate(event)}" instead of "${event}".`); + } + } + // convert handler name to camelCase. See issue #2249 + let handlerName = toHandlerKey(camelize(event)); let handler = props[handlerName]; // for v-model update:xxx events, also trigger kebab-case equivalent // for props passed via kebab-case - if (!handler && event.startsWith('update:')) { - handlerName = `on${capitalize(hyphenate(event))}`; + if (!handler && isModelListener) { + handlerName = toHandlerKey(hyphenate(event)); handler = props[handlerName]; } - if (!handler) { - handler = props[handlerName + `Once`]; + if (handler) { + callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); + } + const onceHandler = props[handlerName + `Once`]; + if (onceHandler) { if (!instance.emitted) { (instance.emitted = {})[handlerName] = true; } else if (instance.emitted[handlerName]) { return; } - } - if (handler) { - callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); + callWithAsyncErrorHandling(onceHandler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { - const appId = appContext.app ? appContext.app._uid : -1; - const cache = comp.__emits || (comp.__emits = {}); - const cached = cache[appId]; - if (cached !== undefined) { - return cached; + if (!appContext.deopt && comp.__emits !== undefined) { + return comp.__emits; } const raw = comp.emits; let normalized = {}; @@ -1464,7 +1487,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (cache[appId] = null); + return (comp.__emits = null); } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -1472,7 +1495,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { else { extend(normalized, raw); } - return (cache[appId] = normalized); + return (comp.__emits = normalized); } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are @@ -1603,7 +1626,7 @@ function renderComponentRoot(instance) { warn(`Runtime directive used on component with non-element root node. ` + `The directives will not function as intended.`); } - root.dirs = vnode.dirs; + root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs; } // inherit transition data if (vnode.transition) { @@ -1647,11 +1670,13 @@ const getChildRoot = (vnode) => { const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1; const setRoot = (updatedRoot) => { rawChildren[index] = updatedRoot; - if (dynamicIndex > -1) { - dynamicChildren[dynamicIndex] = updatedRoot; - } - else if (dynamicChildren && updatedRoot.patchFlag > 0) { - dynamicChildren.push(updatedRoot); + if (dynamicChildren) { + if (dynamicIndex > -1) { + dynamicChildren[dynamicIndex] = updatedRoot; + } + else if (updatedRoot.patchFlag > 0) { + vnode.dynamicChildren = [...dynamicChildren, updatedRoot]; + } } }; return [normalizeVNode(childRoot), setRoot]; @@ -1789,7 +1814,7 @@ const SuspenseImpl = { mountSuspense(n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, rendererInternals); } else { - patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimized, rendererInternals); + patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, rendererInternals); } }, hydrate: hydrateSuspense, @@ -1803,13 +1828,13 @@ function mountSuspense(vnode, container, anchor, parentComponent, parentSuspense const hiddenContainer = createElement('div'); const suspense = (vnode.suspense = createSuspenseBoundary(vnode, parentSuspense, parentComponent, container, hiddenContainer, anchor, isSVG, optimized, rendererInternals)); // start mounting the content subtree in an off-dom container - patch(null, (suspense.pendingBranch = vnode.ssContent), hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(null, (suspense.pendingBranch = vnode.ssContent), hiddenContainer, null, parentComponent, suspense, isSVG); // now check if we have encountered any async deps if (suspense.deps > 0) { // has async // mount the fallback tree patch(null, vnode.ssFallback, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); + isSVG); setActiveBranch(suspense, vnode.ssFallback); } else { @@ -1817,7 +1842,7 @@ function mountSuspense(vnode, container, anchor, parentComponent, parentSuspense suspense.resolve(); } } -function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimized, { p: patch, um: unmount, o: { createElement } }) { +function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, { p: patch, um: unmount, o: { createElement } }) { const suspense = (n2.suspense = n1.suspense); suspense.vnode = n2; n2.el = n1.el; @@ -1828,13 +1853,13 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimi suspense.pendingBranch = newBranch; if (isSameVNodeType(newBranch, pendingBranch)) { // same root type but content may have changed. - patch(pendingBranch, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(pendingBranch, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG); if (suspense.deps <= 0) { suspense.resolve(); } else if (isInFallback) { patch(activeBranch, newFallback, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); + isSVG); setActiveBranch(suspense, newFallback); } } @@ -1860,25 +1885,25 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimi suspense.hiddenContainer = createElement('div'); if (isInFallback) { // already in fallback state - patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG); if (suspense.deps <= 0) { suspense.resolve(); } else { patch(activeBranch, newFallback, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); + isSVG); setActiveBranch(suspense, newFallback); } } else if (activeBranch && isSameVNodeType(newBranch, activeBranch)) { // toggled "back" to current active branch - patch(activeBranch, newBranch, container, anchor, parentComponent, suspense, isSVG, optimized); + patch(activeBranch, newBranch, container, anchor, parentComponent, suspense, isSVG); // force resolve suspense.resolve(true); } else { // switched to a 3rd branch - patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG); if (suspense.deps <= 0) { suspense.resolve(); } @@ -1888,7 +1913,7 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimi else { if (activeBranch && isSameVNodeType(newBranch, activeBranch)) { // root did not change, just normal patch - patch(activeBranch, newBranch, container, anchor, parentComponent, suspense, isSVG, optimized); + patch(activeBranch, newBranch, container, anchor, parentComponent, suspense, isSVG); setActiveBranch(suspense, newBranch); } else { @@ -1901,7 +1926,7 @@ function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimi // mount pending branch in off-dom container suspense.pendingBranch = newBranch; suspense.pendingId++; - patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); + patch(null, newBranch, suspense.hiddenContainer, null, parentComponent, suspense, isSVG); if (suspense.deps <= 0) { // incoming branch has no async deps, resolve now. suspense.resolve(); @@ -1937,7 +1962,6 @@ function createSuspenseBoundary(vnode, parent, parentComponent, container, hidde parent, parentComponent, isSVG, - optimized, container, hiddenContainer, anchor, @@ -2020,7 +2044,7 @@ function createSuspenseBoundary(vnode, parent, parentComponent, container, hidde if (!suspense.pendingBranch) { return; } - const { vnode, activeBranch, parentComponent, container, isSVG, optimized } = suspense; + const { vnode, activeBranch, parentComponent, container, isSVG } = suspense; // invoke @fallback event const onFallback = vnode.props && vnode.props.onFallback; if (isFunction(onFallback)) { @@ -2033,7 +2057,7 @@ function createSuspenseBoundary(vnode, parent, parentComponent, container, hidde } // mount the fallback tree patch(null, fallbackVNode, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); + isSVG); setActiveBranch(suspense, fallbackVNode); }; const delayEnter = fallbackVNode.transition && fallbackVNode.transition.mode === 'out-in'; @@ -2277,1128 +2301,655 @@ function withScopeId(id) { })); } -const isTeleport = (type) => type.__isTeleport; -const isTeleportDisabled = (props) => props && (props.disabled || props.disabled === ''); -const resolveTarget = (props, select) => { - const targetSelector = props && props.to; - if (isString(targetSelector)) { - if (!select) { - (process.env.NODE_ENV !== 'production') && - warn(`Current renderer does not support string target for Teleports. ` + - `(missing querySelector renderer option)`); - return null; - } - else { - const target = select(targetSelector); - if (!target) { - (process.env.NODE_ENV !== 'production') && - warn(`Failed to locate Teleport target with selector "${targetSelector}". ` + - `Note the target element must exist before the component is mounted - ` + - `i.e. the target cannot be rendered by the component itself, and ` + - `ideally should be outside of the entire Vue component tree.`); - } - return target; - } +function initProps(instance, rawProps, isStateful, // result of bitwise flag comparison +isSSR = false) { + const props = {}; + const attrs = {}; + def(attrs, InternalObjectKey, 1); + setFullProps(instance, rawProps, props, attrs); + // validation + if ((process.env.NODE_ENV !== 'production')) { + validateProps(props, instance); } - else { - if ((process.env.NODE_ENV !== 'production') && !targetSelector && !isTeleportDisabled(props)) { - warn(`Invalid Teleport target: ${targetSelector}`); - } - return targetSelector; + if (isStateful) { + // stateful + instance.props = isSSR ? props : shallowReactive(props); } -}; -const TeleportImpl = { - __isTeleport: true, - process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals) { - const { mc: mountChildren, pc: patchChildren, pbc: patchBlockChildren, o: { insert, querySelector, createText, createComment } } = internals; - const disabled = isTeleportDisabled(n2.props); - const { shapeFlag, children } = n2; - if (n1 == null) { - // insert anchors in the main view - const placeholder = (n2.el = (process.env.NODE_ENV !== 'production') - ? createComment('teleport start') - : createText('')); - const mainAnchor = (n2.anchor = (process.env.NODE_ENV !== 'production') - ? createComment('teleport end') - : createText('')); - insert(placeholder, container, anchor); - insert(mainAnchor, container, anchor); - const target = (n2.target = resolveTarget(n2.props, querySelector)); - const targetAnchor = (n2.targetAnchor = createText('')); - if (target) { - insert(targetAnchor, target); - } - else if ((process.env.NODE_ENV !== 'production') && !disabled) { - warn('Invalid Teleport target on mount:', target, `(${typeof target})`); - } - const mount = (container, anchor) => { - // Teleport *always* has Array children. This is enforced in both the - // compiler and vnode children normalization. - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - mountChildren(children, container, anchor, parentComponent, parentSuspense, isSVG, optimized); - } - }; - if (disabled) { - mount(container, mainAnchor); - } - else if (target) { - mount(target, targetAnchor); - } + else { + if (!instance.type.props) { + // functional w/ optional props, props === attrs + instance.props = attrs; } else { - // update content - n2.el = n1.el; - const mainAnchor = (n2.anchor = n1.anchor); - const target = (n2.target = n1.target); - const targetAnchor = (n2.targetAnchor = n1.targetAnchor); - const wasDisabled = isTeleportDisabled(n1.props); - const currentContainer = wasDisabled ? container : target; - const currentAnchor = wasDisabled ? mainAnchor : targetAnchor; - if (n2.dynamicChildren) { - // fast path when the teleport happens to be a block root - patchBlockChildren(n1.dynamicChildren, n2.dynamicChildren, currentContainer, parentComponent, parentSuspense, isSVG); - // even in block tree mode we need to make sure all root-level nodes - // in the teleport inherit previous DOM references so that they can - // be moved in future patches. - if (n2.shapeFlag & 16 /* ARRAY_CHILDREN */) { - const oldChildren = n1.children; - const children = n2.children; - for (let i = 0; i < children.length; i++) { - // only inherit for non-patched nodes (i.e. static ones) - if (!children[i].el) { - children[i].el = oldChildren[i].el; - } + // functional w/ declared props + instance.props = props; + } + } + instance.attrs = attrs; +} +function updateProps(instance, rawProps, rawPrevProps, optimized) { + const { props, attrs, vnode: { patchFlag } } = instance; + const rawCurrentProps = toRaw(props); + const [options] = instance.propsOptions; + if ( + // always force full diff in dev + // - #1942 if hmr is enabled with sfc component + // - vite#872 non-sfc component used by sfc component + !((process.env.NODE_ENV !== 'production') && + (instance.type.__hmrId || + (instance.parent && instance.parent.type.__hmrId))) && + (optimized || patchFlag > 0) && + !(patchFlag & 16 /* FULL_PROPS */)) { + if (patchFlag & 8 /* PROPS */) { + // Compiler-generated props & no keys change, just set the updated + // the props. + const propsToUpdate = instance.vnode.dynamicProps; + for (let i = 0; i < propsToUpdate.length; i++) { + const key = propsToUpdate[i]; + // PROPS flag guarantees rawProps to be non-null + const value = rawProps[key]; + if (options) { + // attr / props separation was done on init and will be consistent + // in this code path, so just check if attrs have it. + if (hasOwn(attrs, key)) { + attrs[key] = value; + } + else { + const camelizedKey = camelize(key); + props[camelizedKey] = resolvePropValue(options, rawCurrentProps, camelizedKey, value, instance); } } - } - else if (!optimized) { - patchChildren(n1, n2, currentContainer, currentAnchor, parentComponent, parentSuspense, isSVG); - } - if (disabled) { - if (!wasDisabled) { - // enabled -> disabled - // move into main container - moveTeleport(n2, container, mainAnchor, internals, 1 /* TOGGLE */); + else { + attrs[key] = value; } } - else { - // target changed - if ((n2.props && n2.props.to) !== (n1.props && n1.props.to)) { - const nextTarget = (n2.target = resolveTarget(n2.props, querySelector)); - if (nextTarget) { - moveTeleport(n2, nextTarget, null, internals, 0 /* TARGET_CHANGE */); - } - else if ((process.env.NODE_ENV !== 'production')) { - warn('Invalid Teleport target on update:', target, `(${typeof target})`); + } + } + else { + // full props update. + setFullProps(instance, rawProps, props, attrs); + // in case of dynamic props, check if we need to delete keys from + // the props object + let kebabKey; + for (const key in rawCurrentProps) { + if (!rawProps || + // for camelCase + (!hasOwn(rawProps, key) && + // it's possible the original props was passed in as kebab-case + // and converted to camelCase (#955) + ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey)))) { + if (options) { + if (rawPrevProps && + // for camelCase + (rawPrevProps[key] !== undefined || + // for kebab-case + rawPrevProps[kebabKey] !== undefined)) { + props[key] = resolvePropValue(options, rawProps || EMPTY_OBJ, key, undefined, instance); } } - else if (wasDisabled) { - // disabled -> enabled - // move into teleport target - moveTeleport(n2, target, targetAnchor, internals, 1 /* TOGGLE */); + else { + delete props[key]; } } } - }, - remove(vnode, { r: remove, o: { remove: hostRemove } }) { - const { shapeFlag, children, anchor } = vnode; - hostRemove(anchor); - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - for (let i = 0; i < children.length; i++) { - remove(children[i]); + // in the case of functional component w/o props declaration, props and + // attrs point to the same object so it should already have been updated. + if (attrs !== rawCurrentProps) { + for (const key in attrs) { + if (!rawProps || !hasOwn(rawProps, key)) { + delete attrs[key]; + } } } - }, - move: moveTeleport, - hydrate: hydrateTeleport -}; -function moveTeleport(vnode, container, parentAnchor, { o: { insert }, m: move }, moveType = 2 /* REORDER */) { - // move target anchor if this is a target change. - if (moveType === 0 /* TARGET_CHANGE */) { - insert(vnode.targetAnchor, container, parentAnchor); } - const { el, anchor, shapeFlag, children, props } = vnode; - const isReorder = moveType === 2 /* REORDER */; - // move main view anchor if this is a re-order. - if (isReorder) { - insert(el, container, parentAnchor); + // trigger updates for $attrs in case it's used in component slots + trigger(instance, "set" /* SET */, '$attrs'); + if ((process.env.NODE_ENV !== 'production') && rawProps) { + validateProps(props, instance); } - // if this is a re-order and teleport is enabled (content is in target) - // do not move children. So the opposite is: only move children if this - // is not a reorder, or the teleport is disabled - if (!isReorder || isTeleportDisabled(props)) { - // Teleport has either Array children or no children. - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - for (let i = 0; i < children.length; i++) { - move(children[i], container, parentAnchor, 2 /* REORDER */); +} +function setFullProps(instance, rawProps, props, attrs) { + const [options, needCastKeys] = instance.propsOptions; + if (rawProps) { + for (const key in rawProps) { + const value = rawProps[key]; + // key, ref are reserved and never passed down + if (isReservedProp(key)) { + continue; + } + // prop option names are camelized during normalization, so to support + // kebab -> camel conversion here we need to camelize the key. + let camelKey; + if (options && hasOwn(options, (camelKey = camelize(key)))) { + props[camelKey] = value; + } + else if (!isEmitListener(instance.emitsOptions, key)) { + // Any non-declared (either as a prop or an emitted event) props are put + // into a separate `attrs` object for spreading. Make sure to preserve + // original key casing + attrs[key] = value; } } } - // move main view anchor if this is a re-order. - if (isReorder) { - insert(anchor, container, parentAnchor); + if (needCastKeys) { + const rawCurrentProps = toRaw(props); + for (let i = 0; i < needCastKeys.length; i++) { + const key = needCastKeys[i]; + props[key] = resolvePropValue(options, rawCurrentProps, key, rawCurrentProps[key], instance); + } } } -function hydrateTeleport(node, vnode, parentComponent, parentSuspense, optimized, { o: { nextSibling, parentNode, querySelector } }, hydrateChildren) { - const target = (vnode.target = resolveTarget(vnode.props, querySelector)); - if (target) { - // if multiple teleports rendered to the same target element, we need to - // pick up from where the last teleport finished instead of the first node - const targetNode = target._lpa || target.firstChild; - if (vnode.shapeFlag & 16 /* ARRAY_CHILDREN */) { - if (isTeleportDisabled(vnode.props)) { - vnode.anchor = hydrateChildren(nextSibling(node), vnode, parentNode(node), parentComponent, parentSuspense, optimized); - vnode.targetAnchor = targetNode; +function resolvePropValue(options, props, key, value, instance) { + const opt = options[key]; + if (opt != null) { + const hasDefault = hasOwn(opt, 'default'); + // default values + if (hasDefault && value === undefined) { + const defaultValue = opt.default; + if (opt.type !== Function && isFunction(defaultValue)) { + setCurrentInstance(instance); + value = defaultValue(props); + setCurrentInstance(null); } else { - vnode.anchor = nextSibling(node); - vnode.targetAnchor = hydrateChildren(targetNode, vnode, target, parentComponent, parentSuspense, optimized); + value = defaultValue; + } + } + // boolean casting + if (opt[0 /* shouldCast */]) { + if (!hasOwn(props, key) && !hasDefault) { + value = false; + } + else if (opt[1 /* shouldCastTrue */] && + (value === '' || value === hyphenate(key))) { + value = true; } - target._lpa = - vnode.targetAnchor && nextSibling(vnode.targetAnchor); } } - return vnode.anchor && nextSibling(vnode.anchor); -} -// Force-casted public typing for h and TSX props inference -const Teleport = TeleportImpl; - -const COMPONENTS = 'components'; -const DIRECTIVES = 'directives'; -/** - * @private - */ -function resolveComponent(name) { - return resolveAsset(COMPONENTS, name) || name; + return value; } -const NULL_DYNAMIC_COMPONENT = Symbol(); -/** - * @private - */ -function resolveDynamicComponent(component) { - if (isString(component)) { - return resolveAsset(COMPONENTS, component, false) || component; +function normalizePropsOptions(comp, appContext, asMixin = false) { + if (!appContext.deopt && comp.__props) { + return comp.__props; } - else { - // invalid types will fallthrough to createVNode and raise warning - return (component || NULL_DYNAMIC_COMPONENT); + const raw = comp.props; + const normalized = {}; + const needCastKeys = []; + // apply mixin/extends props + let hasExtends = false; + if (__VUE_OPTIONS_API__ && !isFunction(comp)) { + const extendProps = (raw) => { + hasExtends = true; + const [props, keys] = normalizePropsOptions(raw, appContext, true); + extend(normalized, props); + if (keys) + needCastKeys.push(...keys); + }; + if (!asMixin && appContext.mixins.length) { + appContext.mixins.forEach(extendProps); + } + if (comp.extends) { + extendProps(comp.extends); + } + if (comp.mixins) { + comp.mixins.forEach(extendProps); + } } -} -/** - * @private - */ -function resolveDirective(name) { - return resolveAsset(DIRECTIVES, name); -} -// implementation -function resolveAsset(type, name, warnMissing = true) { - const instance = currentRenderingInstance || currentInstance; - if (instance) { - const Component = instance.type; - // self name has highest priority - if (type === COMPONENTS) { - const selfName = Component.displayName || Component.name; - if (selfName && - (selfName === name || - selfName === camelize(name) || - selfName === capitalize(camelize(name)))) { - return Component; + if (!raw && !hasExtends) { + return (comp.__props = EMPTY_ARR); + } + if (isArray(raw)) { + for (let i = 0; i < raw.length; i++) { + if ((process.env.NODE_ENV !== 'production') && !isString(raw[i])) { + warn(`props must be strings when using array syntax.`, raw[i]); + } + const normalizedKey = camelize(raw[i]); + if (validatePropName(normalizedKey)) { + normalized[normalizedKey] = EMPTY_OBJ; } } - const res = - // local registration - // check instance[type] first for components with mixin or extends. - resolve(instance[type] || Component[type], name) || - // global registration - resolve(instance.appContext[type], name); - if ((process.env.NODE_ENV !== 'production') && warnMissing && !res) { - warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + } + else if (raw) { + if ((process.env.NODE_ENV !== 'production') && !isObject(raw)) { + warn(`invalid props options`, raw); } - return res; + for (const key in raw) { + const normalizedKey = camelize(key); + if (validatePropName(normalizedKey)) { + const opt = raw[key]; + const prop = (normalized[normalizedKey] = + isArray(opt) || isFunction(opt) ? { type: opt } : opt); + if (prop) { + const booleanIndex = getTypeIndex(Boolean, prop.type); + const stringIndex = getTypeIndex(String, prop.type); + prop[0 /* shouldCast */] = booleanIndex > -1; + prop[1 /* shouldCastTrue */] = + stringIndex < 0 || booleanIndex < stringIndex; + // if the prop needs boolean casting or default value + if (booleanIndex > -1 || hasOwn(prop, 'default')) { + needCastKeys.push(normalizedKey); + } + } + } + } + } + return (comp.__props = [normalized, needCastKeys]); +} +function validatePropName(key) { + if (key[0] !== '$') { + return true; } else if ((process.env.NODE_ENV !== 'production')) { - warn(`resolve${capitalize(type.slice(0, -1))} ` + - `can only be used in render() or setup().`); + warn(`Invalid prop name: "${key}" is a reserved property.`); } + return false; } -function resolve(registry, name) { - return (registry && - (registry[name] || - registry[camelize(name)] || - registry[capitalize(camelize(name))])); -} - -const Fragment = Symbol((process.env.NODE_ENV !== 'production') ? 'Fragment' : undefined); -const Text = Symbol((process.env.NODE_ENV !== 'production') ? 'Text' : undefined); -const Comment = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : undefined); -const Static = Symbol((process.env.NODE_ENV !== 'production') ? 'Static' : undefined); -// Since v-if and v-for are the two possible ways node structure can dynamically -// change, once we consider v-if branches and each v-for fragment a block, we -// can divide a template into nested blocks, and within each block the node -// structure would be stable. This allows us to skip most children diffing -// and only worry about the dynamic nodes (indicated by patch flags). -const blockStack = []; -let currentBlock = null; -/** - * Open a block. - * This must be called before `createBlock`. It cannot be part of `createBlock` - * because the children of the block are evaluated before `createBlock` itself - * is called. The generated code typically looks like this: - * - * ```js - * function render() { - * return (openBlock(),createBlock('div', null, [...])) - * } - * ``` - * disableTracking is true when creating a v-for fragment block, since a v-for - * fragment always diffs its children. - * - * @private - */ -function openBlock(disableTracking = false) { - blockStack.push((currentBlock = disableTracking ? null : [])); +// use function string name to check type constructors +// so that it works across vms / iframes. +function getType(ctor) { + const match = ctor && ctor.toString().match(/^\s*function (\w+)/); + return match ? match[1] : ''; } -function closeBlock() { - blockStack.pop(); - currentBlock = blockStack[blockStack.length - 1] || null; +function isSameType(a, b) { + return getType(a) === getType(b); +} +function getTypeIndex(type, expectedTypes) { + if (isArray(expectedTypes)) { + for (let i = 0, len = expectedTypes.length; i < len; i++) { + if (isSameType(expectedTypes[i], type)) { + return i; + } + } + } + else if (isFunction(expectedTypes)) { + return isSameType(expectedTypes, type) ? 0 : -1; + } + return -1; } -// Whether we should be tracking dynamic child nodes inside a block. -// Only tracks when this value is > 0 -// We are not using a simple boolean because this value may need to be -// incremented/decremented by nested usage of v-once (see below) -let shouldTrack$1 = 1; /** - * Block tracking sometimes needs to be disabled, for example during the - * creation of a tree that needs to be cached by v-once. The compiler generates - * code like this: - * - * ``` js - * _cache[1] || ( - * setBlockTracking(-1), - * _cache[1] = createVNode(...), - * setBlockTracking(1), - * _cache[1] - * ) - * ``` - * - * @private + * dev only */ -function setBlockTracking(value) { - shouldTrack$1 += value; +function validateProps(props, instance) { + const rawValues = toRaw(props); + const options = instance.propsOptions[0]; + for (const key in options) { + let opt = options[key]; + if (opt == null) + continue; + validateProp(key, rawValues[key], opt, !hasOwn(rawValues, key)); + } } /** - * Create a block root vnode. Takes the same exact arguments as `createVNode`. - * A block root keeps track of dynamic nodes within the block in the - * `dynamicChildren` array. - * - * @private + * dev only */ -function createBlock(type, props, children, patchFlag, dynamicProps) { - const vnode = createVNode(type, props, children, patchFlag, dynamicProps, true /* isBlock: prevent a block from tracking itself */); - // save current block children on the block vnode - vnode.dynamicChildren = currentBlock || EMPTY_ARR; - // close block - closeBlock(); - // a block is always going to be patched, so track it as a child of its - // parent block - if (shouldTrack$1 > 0 && currentBlock) { - currentBlock.push(vnode); +function validateProp(name, value, prop, isAbsent) { + const { type, required, validator } = prop; + // required! + if (required && isAbsent) { + warn('Missing required prop: "' + name + '"'); + return; } - return vnode; -} -function isVNode(value) { - return value ? value.__v_isVNode === true : false; -} -function isSameVNodeType(n1, n2) { - if ((process.env.NODE_ENV !== 'production') && - n2.shapeFlag & 6 /* COMPONENT */ && - hmrDirtyComponents.has(n2.type)) { - // HMR only: if the component has been hot-updated, force a reload. - return false; + // missing but optional + if (value == null && !prop.required) { + return; } - return n1.type === n2.type && n1.key === n2.key; -} -let vnodeArgsTransformer; -/** - * Internal API for registering an arguments transform for createVNode - * used for creating stubs in the test-utils - * It is *internal* but needs to be exposed for test-utils to pick up proper - * typings - */ -function transformVNodeArgs(transformer) { - vnodeArgsTransformer = transformer; -} -const createVNodeWithArgsTransform = (...args) => { - return _createVNode(...(vnodeArgsTransformer - ? vnodeArgsTransformer(args, currentRenderingInstance) - : args)); -}; -const InternalObjectKey = `__vInternal`; -const normalizeKey = ({ key }) => key != null ? key : null; -const normalizeRef = ({ ref }) => { - return (ref != null - ? isArray(ref) - ? ref - : { i: currentRenderingInstance, r: ref } - : null); -}; -const createVNode = ((process.env.NODE_ENV !== 'production') - ? createVNodeWithArgsTransform - : _createVNode); -function _createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, isBlockNode = false) { - if (!type || type === NULL_DYNAMIC_COMPONENT) { - if ((process.env.NODE_ENV !== 'production') && !type) { - warn(`Invalid vnode type when creating vnode: ${type}.`); + // type check + if (type != null && type !== true) { + let isValid = false; + const types = isArray(type) ? type : [type]; + const expectedTypes = []; + // value is valid as long as one of the specified types match + for (let i = 0; i < types.length && !isValid; i++) { + const { valid, expectedType } = assertType(value, types[i]); + expectedTypes.push(expectedType || ''); + isValid = valid; } - type = Comment; - } - if (isVNode(type)) { - // createVNode receiving an existing vnode. This happens in cases like - // - // #2078 make sure to merge refs during the clone instead of overwriting it - const cloned = cloneVNode(type, props, true /* mergeRef: true */); - if (children) { - normalizeChildren(cloned, children); + if (!isValid) { + warn(getInvalidTypeMessage(name, value, expectedTypes)); + return; } - return cloned; } - // class component normalization. - if (isClassComponent(type)) { - type = type.__vccOpts; + // custom validator + if (validator && !validator(value)) { + warn('Invalid prop: custom validator check failed for prop "' + name + '".'); } - // class & style normalization. - if (props) { - // for reactive or proxy objects, we need to clone it to enable mutation. - if (isProxy(props) || InternalObjectKey in props) { - props = extend({}, props); - } - let { class: klass, style } = props; - if (klass && !isString(klass)) { - props.class = normalizeClass(klass); - } - if (isObject(style)) { - // reactive state objects need to be cloned since they are likely to be - // mutated - if (isProxy(style) && !isArray(style)) { - style = extend({}, style); - } - props.style = normalizeStyle(style); +} +const isSimpleType = /*#__PURE__*/ makeMap('String,Number,Boolean,Function,Symbol'); +/** + * dev only + */ +function assertType(value, type) { + let valid; + const expectedType = getType(type); + if (isSimpleType(expectedType)) { + const t = typeof value; + valid = t === expectedType.toLowerCase(); + // for primitive wrapper objects + if (!valid && t === 'object') { + valid = value instanceof type; } } - // encode the vnode type information into a bitmap - const shapeFlag = isString(type) - ? 1 /* ELEMENT */ - : isSuspense(type) - ? 128 /* SUSPENSE */ - : isTeleport(type) - ? 64 /* TELEPORT */ - : isObject(type) - ? 4 /* STATEFUL_COMPONENT */ - : isFunction(type) - ? 2 /* FUNCTIONAL_COMPONENT */ - : 0; - if ((process.env.NODE_ENV !== 'production') && shapeFlag & 4 /* STATEFUL_COMPONENT */ && isProxy(type)) { - type = toRaw(type); - warn(`Vue received a Component which was made a reactive object. This can ` + - `lead to unnecessary performance overhead, and should be avoided by ` + - `marking the component with \`markRaw\` or using \`shallowRef\` ` + - `instead of \`ref\`.`, `\nComponent that was made reactive: `, type); - } - const vnode = { - __v_isVNode: true, - ["__v_skip" /* SKIP */]: true, - type, - props, - key: props && normalizeKey(props), - ref: props && normalizeRef(props), - scopeId: currentScopeId, - children: null, - component: null, - suspense: null, - ssContent: null, - ssFallback: null, - dirs: null, - transition: null, - el: null, - anchor: null, - target: null, - targetAnchor: null, - staticCount: 0, - shapeFlag, - patchFlag, - dynamicProps, - dynamicChildren: null, - appContext: null - }; - // validate key - if ((process.env.NODE_ENV !== 'production') && vnode.key !== vnode.key) { - warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type); + else if (expectedType === 'Object') { + valid = isObject(value); } - normalizeChildren(vnode, children); - // normalize suspense children - if ( shapeFlag & 128 /* SUSPENSE */) { - const { content, fallback } = normalizeSuspenseChildren(vnode); - vnode.ssContent = content; - vnode.ssFallback = fallback; + else if (expectedType === 'Array') { + valid = isArray(value); } - if (shouldTrack$1 > 0 && - // avoid a block node from tracking itself - !isBlockNode && - // has current parent block - currentBlock && - // presence of a patch flag indicates this node needs patching on updates. - // component nodes also should always be patched, because even if the - // component doesn't need to update, it needs to persist the instance on to - // the next vnode so that it can be properly unmounted later. - (patchFlag > 0 || shapeFlag & 6 /* COMPONENT */) && - // the EVENTS flag is only for hydration and if it is the only flag, the - // vnode should not be considered dynamic due to handler caching. - patchFlag !== 32 /* HYDRATE_EVENTS */) { - currentBlock.push(vnode); + else { + valid = value instanceof type; } - return vnode; -} -function cloneVNode(vnode, extraProps, mergeRef = false) { - // This is intentionally NOT using spread or extend to avoid the runtime - // key enumeration cost. - const { props, ref, patchFlag } = vnode; - const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props; return { - __v_isVNode: true, - ["__v_skip" /* SKIP */]: true, - type: vnode.type, - props: mergedProps, - key: mergedProps && normalizeKey(mergedProps), - ref: extraProps && extraProps.ref - ? // #2078 in the case of - // if the vnode itself already has a ref, cloneVNode will need to merge - // the refs so the single vnode can be set on multiple refs - mergeRef && ref - ? isArray(ref) - ? ref.concat(normalizeRef(extraProps)) - : [ref, normalizeRef(extraProps)] - : normalizeRef(extraProps) - : ref, - scopeId: vnode.scopeId, - children: vnode.children, - target: vnode.target, - targetAnchor: vnode.targetAnchor, - staticCount: vnode.staticCount, - shapeFlag: vnode.shapeFlag, - // if the vnode is cloned with extra props, we can no longer assume its - // existing patch flag to be reliable and need to add the FULL_PROPS flag. - // note: perserve flag for fragments since they use the flag for children - // fast paths only. - patchFlag: extraProps && vnode.type !== Fragment - ? patchFlag === -1 // hoisted node - ? 16 /* FULL_PROPS */ - : patchFlag | 16 /* FULL_PROPS */ - : patchFlag, - dynamicProps: vnode.dynamicProps, - dynamicChildren: vnode.dynamicChildren, - appContext: vnode.appContext, - dirs: vnode.dirs, - transition: vnode.transition, - // These should technically only be non-null on mounted VNodes. However, - // they *should* be copied for kept-alive vnodes. So we just always copy - // them since them being non-null during a mount doesn't affect the logic as - // they will simply be overwritten. - component: vnode.component, - suspense: vnode.suspense, - ssContent: vnode.ssContent && cloneVNode(vnode.ssContent), - ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback), - el: vnode.el, - anchor: vnode.anchor + valid, + expectedType }; } /** - * @private + * dev only */ -function createTextVNode(text = ' ', flag = 0) { - return createVNode(Text, null, text, flag); -} -/** - * @private - */ -function createStaticVNode(content, numberOfNodes) { - // A static vnode can contain multiple stringified elements, and the number - // of elements is necessary for hydration. - const vnode = createVNode(Static, null, content); - vnode.staticCount = numberOfNodes; - return vnode; +function getInvalidTypeMessage(name, value, expectedTypes) { + let message = `Invalid prop: type check failed for prop "${name}".` + + ` Expected ${expectedTypes.map(capitalize).join(', ')}`; + const expectedType = expectedTypes[0]; + const receivedType = toRawType(value); + const expectedValue = styleValue(value, expectedType); + const receivedValue = styleValue(value, receivedType); + // check if we need to specify expected value + if (expectedTypes.length === 1 && + isExplicable(expectedType) && + !isBoolean(expectedType, receivedType)) { + message += ` with value ${expectedValue}`; + } + message += `, got ${receivedType} `; + // check if we need to specify received value + if (isExplicable(receivedType)) { + message += `with value ${receivedValue}.`; + } + return message; } /** - * @private + * dev only */ -function createCommentVNode(text = '', -// when used as the v-else branch, the comment node must be created as a -// block to ensure correct updates. -asBlock = false) { - return asBlock - ? (openBlock(), createBlock(Comment, null, text)) - : createVNode(Comment, null, text); -} -function normalizeVNode(child) { - if (child == null || typeof child === 'boolean') { - // empty placeholder - return createVNode(Comment); - } - else if (isArray(child)) { - // fragment - return createVNode(Fragment, null, child); +function styleValue(value, type) { + if (type === 'String') { + return `"${value}"`; } - else if (typeof child === 'object') { - // already vnode, this should be the most common since compiled templates - // always produce all-vnode children arrays - return child.el === null ? child : cloneVNode(child); + else if (type === 'Number') { + return `${Number(value)}`; } else { - // strings and numbers - return createVNode(Text, null, String(child)); + return `${value}`; } } -// optimized normalization for template-compiled render fns -function cloneIfMounted(child) { - return child.el === null ? child : cloneVNode(child); +/** + * dev only + */ +function isExplicable(type) { + const explicitTypes = ['string', 'number', 'boolean']; + return explicitTypes.some(elem => type.toLowerCase() === elem); } -function normalizeChildren(vnode, children) { - let type = 0; - const { shapeFlag } = vnode; - if (children == null) { - children = null; - } - else if (isArray(children)) { - type = 16 /* ARRAY_CHILDREN */; - } - else if (typeof children === 'object') { - if (shapeFlag & 1 /* ELEMENT */ || shapeFlag & 64 /* TELEPORT */) { - // Normalize slot to plain children for plain element and Teleport - const slot = children.default; - if (slot) { - // _c marker is added by withCtx() indicating this is a compiled slot - slot._c && setCompiledSlotRendering(1); - normalizeChildren(vnode, slot()); - slot._c && setCompiledSlotRendering(-1); - } - return; +/** + * dev only + */ +function isBoolean(...args) { + return args.some(elem => elem.toLowerCase() === 'boolean'); +} + +function injectHook(type, hook, target = currentInstance, prepend = false) { + if (target) { + const hooks = target[type] || (target[type] = []); + // cache the error handling wrapper for injected hooks so the same hook + // can be properly deduped by the scheduler. "__weh" stands for "with error + // handling". + const wrappedHook = hook.__weh || + (hook.__weh = (...args) => { + if (target.isUnmounted) { + return; + } + // disable tracking inside all lifecycle hooks + // since they can potentially be called inside effects. + pauseTracking(); + // Set currentInstance during hook invocation. + // This assumes the hook does not synchronously trigger other hooks, which + // can only be false when the user does something really funky. + setCurrentInstance(target); + const res = callWithAsyncErrorHandling(hook, target, type, args); + setCurrentInstance(null); + resetTracking(); + return res; + }); + if (prepend) { + hooks.unshift(wrappedHook); } else { - type = 32 /* SLOTS_CHILDREN */; - const slotFlag = children._; - if (!slotFlag && !(InternalObjectKey in children)) { - children._ctx = currentRenderingInstance; - } - else if (slotFlag === 3 /* FORWARDED */ && currentRenderingInstance) { - // a child component receives forwarded slots from the parent. - // its slot type is determined by its parent's slot type. - if (currentRenderingInstance.vnode.patchFlag & 1024 /* DYNAMIC_SLOTS */) { - children._ = 2 /* DYNAMIC */; - vnode.patchFlag |= 1024 /* DYNAMIC_SLOTS */; - } - else { - children._ = 1 /* STABLE */; - } - } + hooks.push(wrappedHook); } + return wrappedHook; } - else if (isFunction(children)) { - children = { default: children, _ctx: currentRenderingInstance }; - type = 32 /* SLOTS_CHILDREN */; + else if ((process.env.NODE_ENV !== 'production')) { + const apiName = toHandlerKey(ErrorTypeStrings[type].replace(/ hook$/, '')); + warn(`${apiName} is called when there is no active component instance to be ` + + `associated with. ` + + `Lifecycle injection APIs can only be used during execution of setup().` + + ( ` If you are using async setup(), make sure to register lifecycle ` + + `hooks before the first await statement.` + )); } - else { - children = String(children); - // force teleport children to array so it can be moved around - if (shapeFlag & 64 /* TELEPORT */) { - type = 16 /* ARRAY_CHILDREN */; - children = [createTextVNode(children)]; +} +const createHook = (lifecycle) => (hook, target = currentInstance) => +// post-create lifecycle registrations are noops during SSR +!isInSSRComponentSetup && injectHook(lifecycle, hook, target); +const onBeforeMount = createHook("bm" /* BEFORE_MOUNT */); +const onMounted = createHook("m" /* MOUNTED */); +const onBeforeUpdate = createHook("bu" /* BEFORE_UPDATE */); +const onUpdated = createHook("u" /* UPDATED */); +const onBeforeUnmount = createHook("bum" /* BEFORE_UNMOUNT */); +const onUnmounted = createHook("um" /* UNMOUNTED */); +const onRenderTriggered = createHook("rtg" /* RENDER_TRIGGERED */); +const onRenderTracked = createHook("rtc" /* RENDER_TRACKED */); +const onErrorCaptured = (hook, target = currentInstance) => { + injectHook("ec" /* ERROR_CAPTURED */, hook, target); +}; + +// Simple effect. +function watchEffect(effect, options) { + return doWatch(effect, null, options); +} +// initial value for watchers to trigger on undefined initial values +const INITIAL_WATCHER_VALUE = {}; +// implementation +function watch(source, cb, options) { + if ((process.env.NODE_ENV !== 'production') && !isFunction(cb)) { + warn(`\`watch(fn, options?)\` signature has been moved to a separate API. ` + + `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + + `supports \`watch(source, cb, options?) signature.`); + } + return doWatch(source, cb, options); +} +function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ, instance = currentInstance) { + if ((process.env.NODE_ENV !== 'production') && !cb) { + if (immediate !== undefined) { + warn(`watch() "immediate" option is only respected when using the ` + + `watch(source, callback, options?) signature.`); } - else { - type = 8 /* TEXT_CHILDREN */; + if (deep !== undefined) { + warn(`watch() "deep" option is only respected when using the ` + + `watch(source, callback, options?) signature.`); } } - vnode.children = children; - vnode.shapeFlag |= type; -} -function mergeProps(...args) { - const ret = extend({}, args[0]); - for (let i = 1; i < args.length; i++) { - const toMerge = args[i]; - for (const key in toMerge) { - if (key === 'class') { - if (ret.class !== toMerge.class) { - ret.class = normalizeClass([ret.class, toMerge.class]); - } + const warnInvalidSource = (s) => { + warn(`Invalid watch source: `, s, `A watch source can only be a getter/effect function, a ref, ` + + `a reactive object, or an array of these types.`); + }; + let getter; + let forceTrigger = false; + if (isRef(source)) { + getter = () => source.value; + forceTrigger = !!source._shallow; + } + else if (isReactive(source)) { + getter = () => source; + deep = true; + } + else if (isArray(source)) { + getter = () => source.map(s => { + if (isRef(s)) { + return s.value; } - else if (key === 'style') { - ret.style = normalizeStyle([ret.style, toMerge.style]); + else if (isReactive(s)) { + return traverse(s); } - else if (isOn(key)) { - const existing = ret[key]; - const incoming = toMerge[key]; - if (existing !== incoming) { - ret[key] = existing - ? [].concat(existing, toMerge[key]) - : incoming; - } + else if (isFunction(s)) { + return callWithErrorHandling(s, instance, 2 /* WATCH_GETTER */); } else { - ret[key] = toMerge[key]; + (process.env.NODE_ENV !== 'production') && warnInvalidSource(s); } + }); + } + else if (isFunction(source)) { + if (cb) { + // getter with cb + getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */); + } + else { + // no cb -> simple effect + getter = () => { + if (instance && instance.isUnmounted) { + return; + } + if (cleanup) { + cleanup(); + } + return callWithErrorHandling(source, instance, 3 /* WATCH_CALLBACK */, [onInvalidate]); + }; } } - return ret; -} - -function initProps(instance, rawProps, isStateful, // result of bitwise flag comparison -isSSR = false) { - const props = {}; - const attrs = {}; - def(attrs, InternalObjectKey, 1); - setFullProps(instance, rawProps, props, attrs); - // validation - if ((process.env.NODE_ENV !== 'production')) { - validateProps(props, instance); - } - if (isStateful) { - // stateful - instance.props = isSSR ? props : shallowReactive(props); - } else { - if (!instance.type.props) { - // functional w/ optional props, props === attrs - instance.props = attrs; - } - else { - // functional w/ declared props - instance.props = props; - } + getter = NOOP; + (process.env.NODE_ENV !== 'production') && warnInvalidSource(source); } - instance.attrs = attrs; -} -function updateProps(instance, rawProps, rawPrevProps, optimized) { - const { props, attrs, vnode: { patchFlag } } = instance; - const rawCurrentProps = toRaw(props); - const [options] = instance.propsOptions; - if ( - // always force full diff if hmr is enabled - !((process.env.NODE_ENV !== 'production') && instance.type.__hmrId) && - (optimized || patchFlag > 0) && - !(patchFlag & 16 /* FULL_PROPS */)) { - if (patchFlag & 8 /* PROPS */) { - // Compiler-generated props & no keys change, just set the updated - // the props. - const propsToUpdate = instance.vnode.dynamicProps; - for (let i = 0; i < propsToUpdate.length; i++) { - const key = propsToUpdate[i]; - // PROPS flag guarantees rawProps to be non-null - const value = rawProps[key]; - if (options) { - // attr / props separation was done on init and will be consistent - // in this code path, so just check if attrs have it. - if (hasOwn(attrs, key)) { - attrs[key] = value; - } - else { - const camelizedKey = camelize(key); - props[camelizedKey] = resolvePropValue(options, rawCurrentProps, camelizedKey, value, instance); - } - } - else { - attrs[key] = value; - } - } - } + if (cb && deep) { + const baseGetter = getter; + getter = () => traverse(baseGetter()); } - else { - // full props update. - setFullProps(instance, rawProps, props, attrs); - // in case of dynamic props, check if we need to delete keys from - // the props object - let kebabKey; - for (const key in rawCurrentProps) { - if (!rawProps || - // for camelCase - (!hasOwn(rawProps, key) && - // it's possible the original props was passed in as kebab-case - // and converted to camelCase (#955) - ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey)))) { - if (options) { - if (rawPrevProps && - // for camelCase - (rawPrevProps[key] !== undefined || - // for kebab-case - rawPrevProps[kebabKey] !== undefined)) { - props[key] = resolvePropValue(options, rawProps || EMPTY_OBJ, key, undefined, instance); - } - } - else { - delete props[key]; - } - } + let cleanup; + const onInvalidate = (fn) => { + cleanup = runner.options.onStop = () => { + callWithErrorHandling(fn, instance, 4 /* WATCH_CLEANUP */); + }; + }; + let oldValue = isArray(source) ? [] : INITIAL_WATCHER_VALUE; + const job = () => { + if (!runner.active) { + return; } - // in the case of functional component w/o props declaration, props and - // attrs point to the same object so it should already have been updated. - if (attrs !== rawCurrentProps) { - for (const key in attrs) { - if (!rawProps || !hasOwn(rawProps, key)) { - delete attrs[key]; + if (cb) { + // watch(source, cb) + const newValue = runner(); + if (deep || forceTrigger || hasChanged(newValue, oldValue)) { + // cleanup before running cb again + if (cleanup) { + cleanup(); } + callWithAsyncErrorHandling(cb, instance, 3 /* WATCH_CALLBACK */, [ + newValue, + // pass undefined as the old value when it's changed for the first time + oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue, + onInvalidate + ]); + oldValue = newValue; } } - } - // trigger updates for $attrs in case it's used in component slots - trigger(instance, "set" /* SET */, '$attrs'); - if ((process.env.NODE_ENV !== 'production') && rawProps) { - validateProps(props, instance); - } -} -function setFullProps(instance, rawProps, props, attrs) { - const [options, needCastKeys] = instance.propsOptions; - if (rawProps) { - for (const key in rawProps) { - const value = rawProps[key]; - // key, ref are reserved and never passed down - if (isReservedProp(key)) { - continue; - } - // prop option names are camelized during normalization, so to support - // kebab -> camel conversion here we need to camelize the key. - let camelKey; - if (options && hasOwn(options, (camelKey = camelize(key)))) { - props[camelKey] = value; - } - else if (!isEmitListener(instance.emitsOptions, key)) { - // Any non-declared (either as a prop or an emitted event) props are put - // into a separate `attrs` object for spreading. Make sure to preserve - // original key casing - attrs[key] = value; - } + else { + // watchEffect + runner(); } + }; + // important: mark the job as a watcher callback so that scheduler knows + // it is allowed to self-trigger (#1727) + job.allowRecurse = !!cb; + let scheduler; + if (flush === 'sync') { + scheduler = job; } - if (needCastKeys) { - const rawCurrentProps = toRaw(props); - for (let i = 0; i < needCastKeys.length; i++) { - const key = needCastKeys[i]; - props[key] = resolvePropValue(options, rawCurrentProps, key, rawCurrentProps[key], instance); - } + else if (flush === 'post') { + scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); } -} -function resolvePropValue(options, props, key, value, instance) { - const opt = options[key]; - if (opt != null) { - const hasDefault = hasOwn(opt, 'default'); - // default values - if (hasDefault && value === undefined) { - const defaultValue = opt.default; - if (opt.type !== Function && isFunction(defaultValue)) { - setCurrentInstance(instance); - value = defaultValue(props); - setCurrentInstance(null); + else { + // default: 'pre' + scheduler = () => { + if (!instance || instance.isMounted) { + queuePreFlushCb(job); } else { - value = defaultValue; - } - } - // boolean casting - if (opt[0 /* shouldCast */]) { - if (!hasOwn(props, key) && !hasDefault) { - value = false; - } - else if (opt[1 /* shouldCastTrue */] && - (value === '' || value === hyphenate(key))) { - value = true; + // with 'pre' option, the first call must happen before + // the component is mounted so it is called synchronously. + job(); } - } - } - return value; -} -function normalizePropsOptions(comp, appContext, asMixin = false) { - const appId = appContext.app ? appContext.app._uid : -1; - const cache = comp.__props || (comp.__props = {}); - const cached = cache[appId]; - if (cached) { - return cached; - } - const raw = comp.props; - const normalized = {}; - const needCastKeys = []; - // apply mixin/extends props - let hasExtends = false; - if (__VUE_OPTIONS_API__ && !isFunction(comp)) { - const extendProps = (raw) => { - hasExtends = true; - const [props, keys] = normalizePropsOptions(raw, appContext, true); - extend(normalized, props); - if (keys) - needCastKeys.push(...keys); }; - if (!asMixin && appContext.mixins.length) { - appContext.mixins.forEach(extendProps); - } - if (comp.extends) { - extendProps(comp.extends); + } + const runner = effect(getter, { + lazy: true, + onTrack, + onTrigger, + scheduler + }); + recordInstanceBoundEffect(runner); + // initial run + if (cb) { + if (immediate) { + job(); } - if (comp.mixins) { - comp.mixins.forEach(extendProps); + else { + oldValue = runner(); } } - if (!raw && !hasExtends) { - return (cache[appId] = EMPTY_ARR); + else if (flush === 'post') { + queuePostRenderEffect(runner, instance && instance.suspense); } - if (isArray(raw)) { - for (let i = 0; i < raw.length; i++) { - if ((process.env.NODE_ENV !== 'production') && !isString(raw[i])) { - warn(`props must be strings when using array syntax.`, raw[i]); - } - const normalizedKey = camelize(raw[i]); - if (validatePropName(normalizedKey)) { - normalized[normalizedKey] = EMPTY_OBJ; - } - } + else { + runner(); } - else if (raw) { - if ((process.env.NODE_ENV !== 'production') && !isObject(raw)) { - warn(`invalid props options`, raw); + return () => { + stop(runner); + if (instance) { + remove(instance.effects, runner); } - for (const key in raw) { - const normalizedKey = camelize(key); - if (validatePropName(normalizedKey)) { - const opt = raw[key]; - const prop = (normalized[normalizedKey] = - isArray(opt) || isFunction(opt) ? { type: opt } : opt); - if (prop) { - const booleanIndex = getTypeIndex(Boolean, prop.type); - const stringIndex = getTypeIndex(String, prop.type); - prop[0 /* shouldCast */] = booleanIndex > -1; - prop[1 /* shouldCastTrue */] = - stringIndex < 0 || booleanIndex < stringIndex; - // if the prop needs boolean casting or default value - if (booleanIndex > -1 || hasOwn(prop, 'default')) { - needCastKeys.push(normalizedKey); - } - } - } - } - } - return (cache[appId] = [normalized, needCastKeys]); -} -// use function string name to check type constructors -// so that it works across vms / iframes. -function getType(ctor) { - const match = ctor && ctor.toString().match(/^\s*function (\w+)/); - return match ? match[1] : ''; -} -function isSameType(a, b) { - return getType(a) === getType(b); -} -function getTypeIndex(type, expectedTypes) { - if (isArray(expectedTypes)) { - for (let i = 0, len = expectedTypes.length; i < len; i++) { - if (isSameType(expectedTypes[i], type)) { - return i; - } - } - } - else if (isFunction(expectedTypes)) { - return isSameType(expectedTypes, type) ? 0 : -1; - } - return -1; -} -/** - * dev only - */ -function validateProps(props, instance) { - const rawValues = toRaw(props); - const options = instance.propsOptions[0]; - for (const key in options) { - let opt = options[key]; - if (opt == null) - continue; - validateProp(key, rawValues[key], opt, !hasOwn(rawValues, key)); - } + }; } -/** - * dev only - */ -function validatePropName(key) { - if (key[0] !== '$') { - return true; - } - else if ((process.env.NODE_ENV !== 'production')) { - warn(`Invalid prop name: "${key}" is a reserved property.`); - } - return false; +// this.$watch +function instanceWatch(source, cb, options) { + const publicThis = this.proxy; + const getter = isString(source) + ? () => publicThis[source] + : source.bind(publicThis); + return doWatch(getter, cb.bind(publicThis), options, this); } -/** - * dev only - */ -function validateProp(name, value, prop, isAbsent) { - const { type, required, validator } = prop; - // required! - if (required && isAbsent) { - warn('Missing required prop: "' + name + '"'); - return; - } - // missing but optional - if (value == null && !prop.required) { - return; - } - // type check - if (type != null && type !== true) { - let isValid = false; - const types = isArray(type) ? type : [type]; - const expectedTypes = []; - // value is valid as long as one of the specified types match - for (let i = 0; i < types.length && !isValid; i++) { - const { valid, expectedType } = assertType(value, types[i]); - expectedTypes.push(expectedType || ''); - isValid = valid; - } - if (!isValid) { - warn(getInvalidTypeMessage(name, value, expectedTypes)); - return; - } +function traverse(value, seen = new Set()) { + if (!isObject(value) || seen.has(value)) { + return value; } - // custom validator - if (validator && !validator(value)) { - warn('Invalid prop: custom validator check failed for prop "' + name + '".'); + seen.add(value); + if (isRef(value)) { + traverse(value.value, seen); } -} -const isSimpleType = /*#__PURE__*/ makeMap('String,Number,Boolean,Function,Symbol'); -/** - * dev only - */ -function assertType(value, type) { - let valid; - const expectedType = getType(type); - if (isSimpleType(expectedType)) { - const t = typeof value; - valid = t === expectedType.toLowerCase(); - // for primitive wrapper objects - if (!valid && t === 'object') { - valid = value instanceof type; + else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + traverse(value[i], seen); } } - else if (expectedType === 'Object') { - valid = isObject(value); - } - else if (expectedType === 'Array') { - valid = isArray(value); - } - else { - valid = value instanceof type; - } - return { - valid, - expectedType - }; -} -/** - * dev only - */ -function getInvalidTypeMessage(name, value, expectedTypes) { - let message = `Invalid prop: type check failed for prop "${name}".` + - ` Expected ${expectedTypes.map(capitalize).join(', ')}`; - const expectedType = expectedTypes[0]; - const receivedType = toRawType(value); - const expectedValue = styleValue(value, expectedType); - const receivedValue = styleValue(value, receivedType); - // check if we need to specify expected value - if (expectedTypes.length === 1 && - isExplicable(expectedType) && - !isBoolean(expectedType, receivedType)) { - message += ` with value ${expectedValue}`; - } - message += `, got ${receivedType} `; - // check if we need to specify received value - if (isExplicable(receivedType)) { - message += `with value ${receivedValue}.`; - } - return message; -} -/** - * dev only - */ -function styleValue(value, type) { - if (type === 'String') { - return `"${value}"`; - } - else if (type === 'Number') { - return `${Number(value)}`; + else if (isSet(value) || isMap(value)) { + value.forEach((v) => { + traverse(v, seen); + }); } else { - return `${value}`; - } -} -/** - * dev only - */ -function isExplicable(type) { - const explicitTypes = ['string', 'number', 'boolean']; - return explicitTypes.some(elem => type.toLowerCase() === elem); -} -/** - * dev only - */ -function isBoolean(...args) { - return args.some(elem => elem.toLowerCase() === 'boolean'); -} - -function injectHook(type, hook, target = currentInstance, prepend = false) { - if (target) { - const hooks = target[type] || (target[type] = []); - // cache the error handling wrapper for injected hooks so the same hook - // can be properly deduped by the scheduler. "__weh" stands for "with error - // handling". - const wrappedHook = hook.__weh || - (hook.__weh = (...args) => { - if (target.isUnmounted) { - return; - } - // disable tracking inside all lifecycle hooks - // since they can potentially be called inside effects. - pauseTracking(); - // Set currentInstance during hook invocation. - // This assumes the hook does not synchronously trigger other hooks, which - // can only be false when the user does something really funky. - setCurrentInstance(target); - const res = callWithAsyncErrorHandling(hook, target, type, args); - setCurrentInstance(null); - resetTracking(); - return res; - }); - if (prepend) { - hooks.unshift(wrappedHook); - } - else { - hooks.push(wrappedHook); + for (const key in value) { + traverse(value[key], seen); } - return wrappedHook; } - else if ((process.env.NODE_ENV !== 'production')) { - const apiName = `on${capitalize(ErrorTypeStrings[type].replace(/ hook$/, ''))}`; - warn(`${apiName} is called when there is no active component instance to be ` + - `associated with. ` + - `Lifecycle injection APIs can only be used during execution of setup().` + - ( ` If you are using async setup(), make sure to register lifecycle ` + - `hooks before the first await statement.` - )); - } -} -const createHook = (lifecycle) => (hook, target = currentInstance) => -// post-create lifecycle registrations are noops during SSR -!isInSSRComponentSetup && injectHook(lifecycle, hook, target); -const onBeforeMount = createHook("bm" /* BEFORE_MOUNT */); -const onMounted = createHook("m" /* MOUNTED */); -const onBeforeUpdate = createHook("bu" /* BEFORE_UPDATE */); -const onUpdated = createHook("u" /* UPDATED */); -const onBeforeUnmount = createHook("bum" /* BEFORE_UNMOUNT */); -const onUnmounted = createHook("um" /* UNMOUNTED */); -const onRenderTriggered = createHook("rtg" /* RENDER_TRIGGERED */); -const onRenderTracked = createHook("rtc" /* RENDER_TRACKED */); -const onErrorCaptured = (hook, target = currentInstance) => { - injectHook("ec" /* ERROR_CAPTURED */, hook, target); -}; + return value; +} function useTransitionState() { const state = { @@ -4215,6 +3766,11 @@ function createAppAPI(render, hydrate) { if (__VUE_OPTIONS_API__) { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin); + // global mixin with props/emits de-optimizes props/emits + // normalization caching. + if (mixin.props || mixin.emits) { + context.deopt = true; + } } else if ((process.env.NODE_ENV !== 'production')) { warn('Mixin has already been applied to target app' + @@ -5037,7 +4593,7 @@ function baseCreateRenderer(options, createHydrationFns) { if (dirs) { invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate'); } - if ((process.env.NODE_ENV !== 'production') && isHmrUpdating) { + if ((process.env.NODE_ENV !== 'production') && (true ) && isHmrUpdating) { // HMR updated, force full diff patchFlag = 0; optimized = false; @@ -5100,7 +4656,10 @@ function baseCreateRenderer(options, createHydrationFns) { const areChildrenSVG = isSVG && n2.type !== 'foreignObject'; if (dynamicChildren) { patchBlockChildren(n1.dynamicChildren, dynamicChildren, el, parentComponent, parentSuspense, areChildrenSVG); - if ((process.env.NODE_ENV !== 'production') && parentComponent && parentComponent.type.__hmrId) { + if ((process.env.NODE_ENV !== 'production') && + (true ) && + parentComponent && + parentComponent.type.__hmrId) { traverseStaticChildren(n1, n2); } } @@ -5141,6 +4700,7 @@ function baseCreateRenderer(options, createHydrationFns) { const patchProps = (el, vnode, oldProps, newProps, parentComponent, parentSuspense, isSVG) => { if (oldProps !== newProps) { for (const key in newProps) { + // empty string is not valid prop if (isReservedProp(key)) continue; const next = newProps[key]; @@ -5224,7 +4784,7 @@ function baseCreateRenderer(options, createHydrationFns) { }; const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => { const instance = (initialVNode.component = createComponentInstance(initialVNode, parentComponent, parentSuspense)); - if ((process.env.NODE_ENV !== 'production') && instance.type.__hmrId) { + if ((process.env.NODE_ENV !== 'production') && (true ) && instance.type.__hmrId) { registerHMR(instance); } if ((process.env.NODE_ENV !== 'production')) { @@ -5369,12 +4929,12 @@ function baseCreateRenderer(options, createHydrationFns) { pushWarningContext(next || instance.vnode); } if (next) { + next.el = vnode.el; updateComponentPreRender(instance, next, optimized); } else { next = vnode; } - next.el = vnode.el; // beforeUpdate hook if (bu) { invokeArrayFns(bu); @@ -5393,11 +4953,6 @@ function baseCreateRenderer(options, createHydrationFns) { } const prevTree = instance.subTree; instance.subTree = nextTree; - // reset refs - // only needed if previous patch had refs - if (instance.refs !== EMPTY_OBJ) { - instance.refs = {}; - } if ((process.env.NODE_ENV !== 'production')) { startMeasure(instance, `patch`); } @@ -5515,7 +5070,7 @@ function baseCreateRenderer(options, createHydrationFns) { } if (oldLength > newLength) { // remove old - unmountChildren(c1, parentComponent, parentSuspense, true, commonLength); + unmountChildren(c1, parentComponent, parentSuspense, true, false, commonLength); } else { // mount new @@ -5752,7 +5307,7 @@ function baseCreateRenderer(options, createHydrationFns) { hostInsert(el, container, anchor); } }; - const unmount = (vnode, parentComponent, parentSuspense, doRemove = false) => { + const unmount = (vnode, parentComponent, parentSuspense, doRemove = false, optimized = false) => { const { type, props, ref, children, dynamicChildren, shapeFlag, patchFlag, dirs } = vnode; // unset ref if (ref != null && parentComponent) { @@ -5783,13 +5338,17 @@ function baseCreateRenderer(options, createHydrationFns) { (type !== Fragment || (patchFlag > 0 && patchFlag & 64 /* STABLE_FRAGMENT */))) { // fast path for block nodes: only need to unmount dynamic children. - unmountChildren(dynamicChildren, parentComponent, parentSuspense); + unmountChildren(dynamicChildren, parentComponent, parentSuspense, false, true); } - else if (shapeFlag & 16 /* ARRAY_CHILDREN */) { + else if ((type === Fragment && + (patchFlag & 128 /* KEYED_FRAGMENT */ || + patchFlag & 256 /* UNKEYED_FRAGMENT */)) || + (!optimized && shapeFlag & 16 /* ARRAY_CHILDREN */)) { unmountChildren(children, parentComponent, parentSuspense); } - // an unmounted teleport should always remove its children - if (shapeFlag & 64 /* TELEPORT */) { + // an unmounted teleport should always remove its children if not disabled + if (shapeFlag & 64 /* TELEPORT */ && + (doRemove || !isTeleportDisabled(vnode.props))) { vnode.type.remove(vnode, internals); } if (doRemove) { @@ -5848,7 +5407,7 @@ function baseCreateRenderer(options, createHydrationFns) { hostRemove(end); }; const unmountComponent = (instance, parentSuspense, doRemove) => { - if ((process.env.NODE_ENV !== 'production') && instance.type.__hmrId) { + if ((process.env.NODE_ENV !== 'production') && (true ) && instance.type.__hmrId) { unregisterHMR(instance); } const { bum, effects, update, subTree, um } = instance; @@ -5893,9 +5452,9 @@ function baseCreateRenderer(options, createHydrationFns) { devtoolsComponentRemoved(instance); } }; - const unmountChildren = (children, parentComponent, parentSuspense, doRemove = false, start = 0) => { + const unmountChildren = (children, parentComponent, parentSuspense, doRemove = false, optimized = false, start = 0) => { for (let i = start; i < children.length; i++) { - unmount(children[i], parentComponent, parentSuspense, doRemove); + unmount(children[i], parentComponent, parentSuspense, doRemove, optimized); } }; const getNextHostNode = vnode => { @@ -5907,39 +5466,6 @@ function baseCreateRenderer(options, createHydrationFns) { } return hostNextSibling((vnode.anchor || vnode.el)); }; - /** - * #1156 - * When a component is HMR-enabled, we need to make sure that all static nodes - * inside a block also inherit the DOM element from the previous tree so that - * HMR updates (which are full updates) can retrieve the element for patching. - * - * #2080 - * Inside keyed `template` fragment static children, if a fragment is moved, - * the children will always moved so that need inherit el form previous nodes - * to ensure correct moved position. - */ - const traverseStaticChildren = (n1, n2, shallow = false) => { - const ch1 = n1.children; - const ch2 = n2.children; - if (isArray(ch1) && isArray(ch2)) { - for (let i = 0; i < ch1.length; i++) { - // this is only called in the optimized path so array children are - // guaranteed to be vnodes - const c1 = ch1[i]; - const c2 = (ch2[i] = cloneIfMounted(ch2[i])); - if (c2.shapeFlag & 1 /* ELEMENT */ && !c2.dynamicChildren) { - if (c2.patchFlag <= 0 || c2.patchFlag === 32 /* HYDRATE_EVENTS */) { - c2.el = c1.el; - } - if (!shallow) - traverseStaticChildren(c1, c2); - } - if ((process.env.NODE_ENV !== 'production') && c2.type === Comment) { - c2.el = c1.el; - } - } - } - }; const render = (vnode, container) => { if (vnode == null) { if (container._vnode) { @@ -5981,6 +5507,42 @@ function invokeVNodeHook(hook, instance, vnode, prevVNode = null) { prevVNode ]); } +/** + * #1156 + * When a component is HMR-enabled, we need to make sure that all static nodes + * inside a block also inherit the DOM element from the previous tree so that + * HMR updates (which are full updates) can retrieve the element for patching. + * + * #2080 + * Inside keyed `template` fragment static children, if a fragment is moved, + * the children will always moved so that need inherit el form previous nodes + * to ensure correct moved position. + */ +function traverseStaticChildren(n1, n2, shallow = false) { + const ch1 = n1.children; + const ch2 = n2.children; + if (isArray(ch1) && isArray(ch2)) { + for (let i = 0; i < ch1.length; i++) { + // this is only called in the optimized path so array children are + // guaranteed to be vnodes + const c1 = ch1[i]; + let c2 = ch2[i]; + if (c2.shapeFlag & 1 /* ELEMENT */ && !c2.dynamicChildren) { + if (c2.patchFlag <= 0 || c2.patchFlag === 32 /* HYDRATE_EVENTS */) { + c2 = ch2[i] = cloneIfMounted(ch2[i]); + c2.el = c1.el; + } + if (!shallow) + traverseStaticChildren(c1, c2); + } + // also inherit for comment nodes, but not placeholders (e.g. v-if which + // would have received .el during block patch) + if ((process.env.NODE_ENV !== 'production') && c2.type === Comment && !c2.el) { + c2.el = c1.el; + } + } + } +} // https://en.wikipedia.org/wiki/Longest_increasing_subsequence function getSequence(arr) { const p = arr.slice(); @@ -6024,210 +5586,667 @@ function getSequence(arr) { return result; } -// Simple effect. -function watchEffect(effect, options) { - return doWatch(effect, null, options); -} -// initial value for watchers to trigger on undefined initial values -const INITIAL_WATCHER_VALUE = {}; -// implementation -function watch(source, cb, options) { - if ((process.env.NODE_ENV !== 'production') && !isFunction(cb)) { - warn(`\`watch(fn, options?)\` signature has been moved to a separate API. ` + - `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + - `supports \`watch(source, cb, options?) signature.`); - } - return doWatch(source, cb, options); -} -function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ, instance = currentInstance) { - if ((process.env.NODE_ENV !== 'production') && !cb) { - if (immediate !== undefined) { - warn(`watch() "immediate" option is only respected when using the ` + - `watch(source, callback, options?) signature.`); +const isTeleport = (type) => type.__isTeleport; +const isTeleportDisabled = (props) => props && (props.disabled || props.disabled === ''); +const resolveTarget = (props, select) => { + const targetSelector = props && props.to; + if (isString(targetSelector)) { + if (!select) { + (process.env.NODE_ENV !== 'production') && + warn(`Current renderer does not support string target for Teleports. ` + + `(missing querySelector renderer option)`); + return null; } - if (deep !== undefined) { - warn(`watch() "deep" option is only respected when using the ` + - `watch(source, callback, options?) signature.`); + else { + const target = select(targetSelector); + if (!target) { + (process.env.NODE_ENV !== 'production') && + warn(`Failed to locate Teleport target with selector "${targetSelector}". ` + + `Note the target element must exist before the component is mounted - ` + + `i.e. the target cannot be rendered by the component itself, and ` + + `ideally should be outside of the entire Vue component tree.`); + } + return target; } } - const warnInvalidSource = (s) => { - warn(`Invalid watch source: `, s, `A watch source can only be a getter/effect function, a ref, ` + - `a reactive object, or an array of these types.`); - }; - let getter; - const isRefSource = isRef(source); - if (isRefSource) { - getter = () => source.value; - } - else if (isReactive(source)) { - getter = () => source; - deep = true; + else { + if ((process.env.NODE_ENV !== 'production') && !targetSelector && !isTeleportDisabled(props)) { + warn(`Invalid Teleport target: ${targetSelector}`); + } + return targetSelector; } - else if (isArray(source)) { - getter = () => source.map(s => { - if (isRef(s)) { - return s.value; +}; +const TeleportImpl = { + __isTeleport: true, + process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals) { + const { mc: mountChildren, pc: patchChildren, pbc: patchBlockChildren, o: { insert, querySelector, createText, createComment } } = internals; + const disabled = isTeleportDisabled(n2.props); + const { shapeFlag, children } = n2; + if (n1 == null) { + // insert anchors in the main view + const placeholder = (n2.el = (process.env.NODE_ENV !== 'production') + ? createComment('teleport start') + : createText('')); + const mainAnchor = (n2.anchor = (process.env.NODE_ENV !== 'production') + ? createComment('teleport end') + : createText('')); + insert(placeholder, container, anchor); + insert(mainAnchor, container, anchor); + const target = (n2.target = resolveTarget(n2.props, querySelector)); + const targetAnchor = (n2.targetAnchor = createText('')); + if (target) { + insert(targetAnchor, target); } - else if (isReactive(s)) { - return traverse(s); + else if ((process.env.NODE_ENV !== 'production') && !disabled) { + warn('Invalid Teleport target on mount:', target, `(${typeof target})`); } - else if (isFunction(s)) { - return callWithErrorHandling(s, instance, 2 /* WATCH_GETTER */); + const mount = (container, anchor) => { + // Teleport *always* has Array children. This is enforced in both the + // compiler and vnode children normalization. + if (shapeFlag & 16 /* ARRAY_CHILDREN */) { + mountChildren(children, container, anchor, parentComponent, parentSuspense, isSVG, optimized); + } + }; + if (disabled) { + mount(container, mainAnchor); } - else { - (process.env.NODE_ENV !== 'production') && warnInvalidSource(s); + else if (target) { + mount(target, targetAnchor); } - }); - } - else if (isFunction(source)) { - if (cb) { - // getter with cb - getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */); } else { - // no cb -> simple effect - getter = () => { - if (instance && instance.isUnmounted) { - return; + // update content + n2.el = n1.el; + const mainAnchor = (n2.anchor = n1.anchor); + const target = (n2.target = n1.target); + const targetAnchor = (n2.targetAnchor = n1.targetAnchor); + const wasDisabled = isTeleportDisabled(n1.props); + const currentContainer = wasDisabled ? container : target; + const currentAnchor = wasDisabled ? mainAnchor : targetAnchor; + if (n2.dynamicChildren) { + // fast path when the teleport happens to be a block root + patchBlockChildren(n1.dynamicChildren, n2.dynamicChildren, currentContainer, parentComponent, parentSuspense, isSVG); + // even in block tree mode we need to make sure all root-level nodes + // in the teleport inherit previous DOM references so that they can + // be moved in future patches. + traverseStaticChildren(n1, n2, true); + } + else if (!optimized) { + patchChildren(n1, n2, currentContainer, currentAnchor, parentComponent, parentSuspense, isSVG); + } + if (disabled) { + if (!wasDisabled) { + // enabled -> disabled + // move into main container + moveTeleport(n2, container, mainAnchor, internals, 1 /* TOGGLE */); } - if (cleanup) { - cleanup(); + } + else { + // target changed + if ((n2.props && n2.props.to) !== (n1.props && n1.props.to)) { + const nextTarget = (n2.target = resolveTarget(n2.props, querySelector)); + if (nextTarget) { + moveTeleport(n2, nextTarget, null, internals, 0 /* TARGET_CHANGE */); + } + else if ((process.env.NODE_ENV !== 'production')) { + warn('Invalid Teleport target on update:', target, `(${typeof target})`); + } } - return callWithErrorHandling(source, instance, 3 /* WATCH_CALLBACK */, [onInvalidate]); - }; + else if (wasDisabled) { + // disabled -> enabled + // move into teleport target + moveTeleport(n2, target, targetAnchor, internals, 1 /* TOGGLE */); + } + } + } + }, + remove(vnode, { r: remove, o: { remove: hostRemove } }) { + const { shapeFlag, children, anchor } = vnode; + hostRemove(anchor); + if (shapeFlag & 16 /* ARRAY_CHILDREN */) { + for (let i = 0; i < children.length; i++) { + remove(children[i]); + } + } + }, + move: moveTeleport, + hydrate: hydrateTeleport +}; +function moveTeleport(vnode, container, parentAnchor, { o: { insert }, m: move }, moveType = 2 /* REORDER */) { + // move target anchor if this is a target change. + if (moveType === 0 /* TARGET_CHANGE */) { + insert(vnode.targetAnchor, container, parentAnchor); + } + const { el, anchor, shapeFlag, children, props } = vnode; + const isReorder = moveType === 2 /* REORDER */; + // move main view anchor if this is a re-order. + if (isReorder) { + insert(el, container, parentAnchor); + } + // if this is a re-order and teleport is enabled (content is in target) + // do not move children. So the opposite is: only move children if this + // is not a reorder, or the teleport is disabled + if (!isReorder || isTeleportDisabled(props)) { + // Teleport has either Array children or no children. + if (shapeFlag & 16 /* ARRAY_CHILDREN */) { + for (let i = 0; i < children.length; i++) { + move(children[i], container, parentAnchor, 2 /* REORDER */); + } + } + } + // move main view anchor if this is a re-order. + if (isReorder) { + insert(anchor, container, parentAnchor); + } +} +function hydrateTeleport(node, vnode, parentComponent, parentSuspense, optimized, { o: { nextSibling, parentNode, querySelector } }, hydrateChildren) { + const target = (vnode.target = resolveTarget(vnode.props, querySelector)); + if (target) { + // if multiple teleports rendered to the same target element, we need to + // pick up from where the last teleport finished instead of the first node + const targetNode = target._lpa || target.firstChild; + if (vnode.shapeFlag & 16 /* ARRAY_CHILDREN */) { + if (isTeleportDisabled(vnode.props)) { + vnode.anchor = hydrateChildren(nextSibling(node), vnode, parentNode(node), parentComponent, parentSuspense, optimized); + vnode.targetAnchor = targetNode; + } + else { + vnode.anchor = nextSibling(node); + vnode.targetAnchor = hydrateChildren(targetNode, vnode, target, parentComponent, parentSuspense, optimized); + } + target._lpa = + vnode.targetAnchor && nextSibling(vnode.targetAnchor); } } + return vnode.anchor && nextSibling(vnode.anchor); +} +// Force-casted public typing for h and TSX props inference +const Teleport = TeleportImpl; + +const COMPONENTS = 'components'; +const DIRECTIVES = 'directives'; +/** + * @private + */ +function resolveComponent(name) { + return resolveAsset(COMPONENTS, name) || name; +} +const NULL_DYNAMIC_COMPONENT = Symbol(); +/** + * @private + */ +function resolveDynamicComponent(component) { + if (isString(component)) { + return resolveAsset(COMPONENTS, component, false) || component; + } + else { + // invalid types will fallthrough to createVNode and raise warning + return (component || NULL_DYNAMIC_COMPONENT); + } +} +/** + * @private + */ +function resolveDirective(name) { + return resolveAsset(DIRECTIVES, name); +} +// implementation +function resolveAsset(type, name, warnMissing = true) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + // self name has highest priority + if (type === COMPONENTS) { + const selfName = Component.displayName || Component.name; + if (selfName && + (selfName === name || + selfName === camelize(name) || + selfName === capitalize(camelize(name)))) { + return Component; + } + } + const res = + // local registration + // check instance[type] first for components with mixin or extends. + resolve(instance[type] || Component[type], name) || + // global registration + resolve(instance.appContext[type], name); + if ((process.env.NODE_ENV !== 'production') && warnMissing && !res) { + warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + } + return res; + } + else if ((process.env.NODE_ENV !== 'production')) { + warn(`resolve${capitalize(type.slice(0, -1))} ` + + `can only be used in render() or setup().`); + } +} +function resolve(registry, name) { + return (registry && + (registry[name] || + registry[camelize(name)] || + registry[capitalize(camelize(name))])); +} + +const Fragment = Symbol((process.env.NODE_ENV !== 'production') ? 'Fragment' : undefined); +const Text = Symbol((process.env.NODE_ENV !== 'production') ? 'Text' : undefined); +const Comment = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : undefined); +const Static = Symbol((process.env.NODE_ENV !== 'production') ? 'Static' : undefined); +// Since v-if and v-for are the two possible ways node structure can dynamically +// change, once we consider v-if branches and each v-for fragment a block, we +// can divide a template into nested blocks, and within each block the node +// structure would be stable. This allows us to skip most children diffing +// and only worry about the dynamic nodes (indicated by patch flags). +const blockStack = []; +let currentBlock = null; +/** + * Open a block. + * This must be called before `createBlock`. It cannot be part of `createBlock` + * because the children of the block are evaluated before `createBlock` itself + * is called. The generated code typically looks like this: + * + * ```js + * function render() { + * return (openBlock(),createBlock('div', null, [...])) + * } + * ``` + * disableTracking is true when creating a v-for fragment block, since a v-for + * fragment always diffs its children. + * + * @private + */ +function openBlock(disableTracking = false) { + blockStack.push((currentBlock = disableTracking ? null : [])); +} +function closeBlock() { + blockStack.pop(); + currentBlock = blockStack[blockStack.length - 1] || null; +} +// Whether we should be tracking dynamic child nodes inside a block. +// Only tracks when this value is > 0 +// We are not using a simple boolean because this value may need to be +// incremented/decremented by nested usage of v-once (see below) +let shouldTrack$1 = 1; +/** + * Block tracking sometimes needs to be disabled, for example during the + * creation of a tree that needs to be cached by v-once. The compiler generates + * code like this: + * + * ``` js + * _cache[1] || ( + * setBlockTracking(-1), + * _cache[1] = createVNode(...), + * setBlockTracking(1), + * _cache[1] + * ) + * ``` + * + * @private + */ +function setBlockTracking(value) { + shouldTrack$1 += value; +} +/** + * Create a block root vnode. Takes the same exact arguments as `createVNode`. + * A block root keeps track of dynamic nodes within the block in the + * `dynamicChildren` array. + * + * @private + */ +function createBlock(type, props, children, patchFlag, dynamicProps) { + const vnode = createVNode(type, props, children, patchFlag, dynamicProps, true /* isBlock: prevent a block from tracking itself */); + // save current block children on the block vnode + vnode.dynamicChildren = currentBlock || EMPTY_ARR; + // close block + closeBlock(); + // a block is always going to be patched, so track it as a child of its + // parent block + if (shouldTrack$1 > 0 && currentBlock) { + currentBlock.push(vnode); + } + return vnode; +} +function isVNode(value) { + return value ? value.__v_isVNode === true : false; +} +function isSameVNodeType(n1, n2) { + if ((process.env.NODE_ENV !== 'production') && + n2.shapeFlag & 6 /* COMPONENT */ && + hmrDirtyComponents.has(n2.type)) { + // HMR only: if the component has been hot-updated, force a reload. + return false; + } + return n1.type === n2.type && n1.key === n2.key; +} +let vnodeArgsTransformer; +/** + * Internal API for registering an arguments transform for createVNode + * used for creating stubs in the test-utils + * It is *internal* but needs to be exposed for test-utils to pick up proper + * typings + */ +function transformVNodeArgs(transformer) { + vnodeArgsTransformer = transformer; +} +const createVNodeWithArgsTransform = (...args) => { + return _createVNode(...(vnodeArgsTransformer + ? vnodeArgsTransformer(args, currentRenderingInstance) + : args)); +}; +const InternalObjectKey = `__vInternal`; +const normalizeKey = ({ key }) => key != null ? key : null; +const normalizeRef = ({ ref }) => { + return (ref != null + ? isArray(ref) + ? ref + : { i: currentRenderingInstance, r: ref } + : null); +}; +const createVNode = ((process.env.NODE_ENV !== 'production') + ? createVNodeWithArgsTransform + : _createVNode); +function _createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, isBlockNode = false) { + if (!type || type === NULL_DYNAMIC_COMPONENT) { + if ((process.env.NODE_ENV !== 'production') && !type) { + warn(`Invalid vnode type when creating vnode: ${type}.`); + } + type = Comment; + } + if (isVNode(type)) { + // createVNode receiving an existing vnode. This happens in cases like + // + // #2078 make sure to merge refs during the clone instead of overwriting it + const cloned = cloneVNode(type, props, true /* mergeRef: true */); + if (children) { + normalizeChildren(cloned, children); + } + return cloned; + } + // class component normalization. + if (isClassComponent(type)) { + type = type.__vccOpts; + } + // class & style normalization. + if (props) { + // for reactive or proxy objects, we need to clone it to enable mutation. + if (isProxy(props) || InternalObjectKey in props) { + props = extend({}, props); + } + let { class: klass, style } = props; + if (klass && !isString(klass)) { + props.class = normalizeClass(klass); + } + if (isObject(style)) { + // reactive state objects need to be cloned since they are likely to be + // mutated + if (isProxy(style) && !isArray(style)) { + style = extend({}, style); + } + props.style = normalizeStyle(style); + } + } + // encode the vnode type information into a bitmap + const shapeFlag = isString(type) + ? 1 /* ELEMENT */ + : isSuspense(type) + ? 128 /* SUSPENSE */ + : isTeleport(type) + ? 64 /* TELEPORT */ + : isObject(type) + ? 4 /* STATEFUL_COMPONENT */ + : isFunction(type) + ? 2 /* FUNCTIONAL_COMPONENT */ + : 0; + if ((process.env.NODE_ENV !== 'production') && shapeFlag & 4 /* STATEFUL_COMPONENT */ && isProxy(type)) { + type = toRaw(type); + warn(`Vue received a Component which was made a reactive object. This can ` + + `lead to unnecessary performance overhead, and should be avoided by ` + + `marking the component with \`markRaw\` or using \`shallowRef\` ` + + `instead of \`ref\`.`, `\nComponent that was made reactive: `, type); + } + const vnode = { + __v_isVNode: true, + ["__v_skip" /* SKIP */]: true, + type, + props, + key: props && normalizeKey(props), + ref: props && normalizeRef(props), + scopeId: currentScopeId, + children: null, + component: null, + suspense: null, + ssContent: null, + ssFallback: null, + dirs: null, + transition: null, + el: null, + anchor: null, + target: null, + targetAnchor: null, + staticCount: 0, + shapeFlag, + patchFlag, + dynamicProps, + dynamicChildren: null, + appContext: null + }; + // validate key + if ((process.env.NODE_ENV !== 'production') && vnode.key !== vnode.key) { + warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type); + } + normalizeChildren(vnode, children); + // normalize suspense children + if ( shapeFlag & 128 /* SUSPENSE */) { + const { content, fallback } = normalizeSuspenseChildren(vnode); + vnode.ssContent = content; + vnode.ssFallback = fallback; + } + if (shouldTrack$1 > 0 && + // avoid a block node from tracking itself + !isBlockNode && + // has current parent block + currentBlock && + // presence of a patch flag indicates this node needs patching on updates. + // component nodes also should always be patched, because even if the + // component doesn't need to update, it needs to persist the instance on to + // the next vnode so that it can be properly unmounted later. + (patchFlag > 0 || shapeFlag & 6 /* COMPONENT */) && + // the EVENTS flag is only for hydration and if it is the only flag, the + // vnode should not be considered dynamic due to handler caching. + patchFlag !== 32 /* HYDRATE_EVENTS */) { + currentBlock.push(vnode); + } + return vnode; +} +function cloneVNode(vnode, extraProps, mergeRef = false) { + // This is intentionally NOT using spread or extend to avoid the runtime + // key enumeration cost. + const { props, ref, patchFlag } = vnode; + const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props; + return { + __v_isVNode: true, + ["__v_skip" /* SKIP */]: true, + type: vnode.type, + props: mergedProps, + key: mergedProps && normalizeKey(mergedProps), + ref: extraProps && extraProps.ref + ? // #2078 in the case of + // if the vnode itself already has a ref, cloneVNode will need to merge + // the refs so the single vnode can be set on multiple refs + mergeRef && ref + ? isArray(ref) + ? ref.concat(normalizeRef(extraProps)) + : [ref, normalizeRef(extraProps)] + : normalizeRef(extraProps) + : ref, + scopeId: vnode.scopeId, + children: vnode.children, + target: vnode.target, + targetAnchor: vnode.targetAnchor, + staticCount: vnode.staticCount, + shapeFlag: vnode.shapeFlag, + // if the vnode is cloned with extra props, we can no longer assume its + // existing patch flag to be reliable and need to add the FULL_PROPS flag. + // note: perserve flag for fragments since they use the flag for children + // fast paths only. + patchFlag: extraProps && vnode.type !== Fragment + ? patchFlag === -1 // hoisted node + ? 16 /* FULL_PROPS */ + : patchFlag | 16 /* FULL_PROPS */ + : patchFlag, + dynamicProps: vnode.dynamicProps, + dynamicChildren: vnode.dynamicChildren, + appContext: vnode.appContext, + dirs: vnode.dirs, + transition: vnode.transition, + // These should technically only be non-null on mounted VNodes. However, + // they *should* be copied for kept-alive vnodes. So we just always copy + // them since them being non-null during a mount doesn't affect the logic as + // they will simply be overwritten. + component: vnode.component, + suspense: vnode.suspense, + ssContent: vnode.ssContent && cloneVNode(vnode.ssContent), + ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback), + el: vnode.el, + anchor: vnode.anchor + }; +} +/** + * @private + */ +function createTextVNode(text = ' ', flag = 0) { + return createVNode(Text, null, text, flag); +} +/** + * @private + */ +function createStaticVNode(content, numberOfNodes) { + // A static vnode can contain multiple stringified elements, and the number + // of elements is necessary for hydration. + const vnode = createVNode(Static, null, content); + vnode.staticCount = numberOfNodes; + return vnode; +} +/** + * @private + */ +function createCommentVNode(text = '', +// when used as the v-else branch, the comment node must be created as a +// block to ensure correct updates. +asBlock = false) { + return asBlock + ? (openBlock(), createBlock(Comment, null, text)) + : createVNode(Comment, null, text); +} +function normalizeVNode(child) { + if (child == null || typeof child === 'boolean') { + // empty placeholder + return createVNode(Comment); + } + else if (isArray(child)) { + // fragment + return createVNode(Fragment, null, child); + } + else if (typeof child === 'object') { + // already vnode, this should be the most common since compiled templates + // always produce all-vnode children arrays + return child.el === null ? child : cloneVNode(child); + } else { - getter = NOOP; - (process.env.NODE_ENV !== 'production') && warnInvalidSource(source); + // strings and numbers + return createVNode(Text, null, String(child)); } - if (cb && deep) { - const baseGetter = getter; - getter = () => traverse(baseGetter()); +} +// optimized normalization for template-compiled render fns +function cloneIfMounted(child) { + return child.el === null ? child : cloneVNode(child); +} +function normalizeChildren(vnode, children) { + let type = 0; + const { shapeFlag } = vnode; + if (children == null) { + children = null; } - let cleanup; - const onInvalidate = (fn) => { - cleanup = runner.options.onStop = () => { - callWithErrorHandling(fn, instance, 4 /* WATCH_CLEANUP */); - }; - }; - let oldValue = isArray(source) ? [] : INITIAL_WATCHER_VALUE; - const job = () => { - if (!runner.active) { + else if (isArray(children)) { + type = 16 /* ARRAY_CHILDREN */; + } + else if (typeof children === 'object') { + if (shapeFlag & 1 /* ELEMENT */ || shapeFlag & 64 /* TELEPORT */) { + // Normalize slot to plain children for plain element and Teleport + const slot = children.default; + if (slot) { + // _c marker is added by withCtx() indicating this is a compiled slot + slot._c && setCompiledSlotRendering(1); + normalizeChildren(vnode, slot()); + slot._c && setCompiledSlotRendering(-1); + } return; } - if (cb) { - // watch(source, cb) - const newValue = runner(); - if (deep || isRefSource || hasChanged(newValue, oldValue)) { - // cleanup before running cb again - if (cleanup) { - cleanup(); + else { + type = 32 /* SLOTS_CHILDREN */; + const slotFlag = children._; + if (!slotFlag && !(InternalObjectKey in children)) { + children._ctx = currentRenderingInstance; + } + else if (slotFlag === 3 /* FORWARDED */ && currentRenderingInstance) { + // a child component receives forwarded slots from the parent. + // its slot type is determined by its parent's slot type. + if (currentRenderingInstance.vnode.patchFlag & 1024 /* DYNAMIC_SLOTS */) { + children._ = 2 /* DYNAMIC */; + vnode.patchFlag |= 1024 /* DYNAMIC_SLOTS */; + } + else { + children._ = 1 /* STABLE */; } - callWithAsyncErrorHandling(cb, instance, 3 /* WATCH_CALLBACK */, [ - newValue, - // pass undefined as the old value when it's changed for the first time - oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue, - onInvalidate - ]); - oldValue = newValue; } } - else { - // watchEffect - runner(); - } - }; - // important: mark the job as a watcher callback so that scheduler knows it - // it is allowed to self-trigger (#1727) - job.allowRecurse = !!cb; - let scheduler; - if (flush === 'sync') { - scheduler = job; } - else if (flush === 'post') { - scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); + else if (isFunction(children)) { + children = { default: children, _ctx: currentRenderingInstance }; + type = 32 /* SLOTS_CHILDREN */; } else { - // default: 'pre' - scheduler = () => { - if (!instance || instance.isMounted) { - queuePreFlushCb(job); - } - else { - // with 'pre' option, the first call must happen before - // the component is mounted so it is called synchronously. - job(); - } - }; - } - const runner = effect(getter, { - lazy: true, - onTrack, - onTrigger, - scheduler - }); - recordInstanceBoundEffect(runner); - // initial run - if (cb) { - if (immediate) { - job(); + children = String(children); + // force teleport children to array so it can be moved around + if (shapeFlag & 64 /* TELEPORT */) { + type = 16 /* ARRAY_CHILDREN */; + children = [createTextVNode(children)]; } else { - oldValue = runner(); + type = 8 /* TEXT_CHILDREN */; } } - else if (flush === 'post') { - queuePostRenderEffect(runner, instance && instance.suspense); - } - else { - runner(); - } - return () => { - stop(runner); - if (instance) { - remove(instance.effects, runner); - } - }; -} -// this.$watch -function instanceWatch(source, cb, options) { - const publicThis = this.proxy; - const getter = isString(source) - ? () => publicThis[source] - : source.bind(publicThis); - return doWatch(getter, cb.bind(publicThis), options, this); + vnode.children = children; + vnode.shapeFlag |= type; } -function traverse(value, seen = new Set()) { - if (!isObject(value) || seen.has(value)) { - return value; - } - seen.add(value); - if (isRef(value)) { - traverse(value.value, seen); - } - else if (isArray(value)) { - for (let i = 0; i < value.length; i++) { - traverse(value[i], seen); - } - } - else if (isMap(value)) { - value.forEach((_, key) => { - // to register mutation dep for existing keys - traverse(value.get(key), seen); - }); - } - else if (isSet(value)) { - value.forEach(v => { - traverse(v, seen); - }); - } - else { - for (const key in value) { - traverse(value[key], seen); +function mergeProps(...args) { + const ret = extend({}, args[0]); + for (let i = 1; i < args.length; i++) { + const toMerge = args[i]; + for (const key in toMerge) { + if (key === 'class') { + if (ret.class !== toMerge.class) { + ret.class = normalizeClass([ret.class, toMerge.class]); + } + } + else if (key === 'style') { + ret.style = normalizeStyle([ret.style, toMerge.style]); + } + else if (isOn(key)) { + const existing = ret[key]; + const incoming = toMerge[key]; + if (existing !== incoming) { + ret[key] = existing + ? [].concat(existing, toMerge[key]) + : incoming; + } + } + else if (key !== '') { + ret[key] = toMerge[key]; + } } } - return value; + return ret; } function provide(key, value) { @@ -6256,8 +6275,13 @@ function inject(key, defaultValue, treatDefaultAsFactory = false) { // a functional component const instance = currentInstance || currentRenderingInstance; if (instance) { - const provides = instance.provides; - if (key in provides) { + // #2400 + // to support `app.use` plugins, + // fallback to appContext's `provides` if the intance is at root + const provides = instance.parent == null + ? instance.vnode.appContext && instance.vnode.appContext.provides + : instance.parent.provides; + if (provides && key in provides) { // TS doesn't allow symbol as index type return provides[key]; } @@ -6287,7 +6311,7 @@ function createDuplicateChecker() { }; } let isInBeforeCreate = false; -function applyOptions(instance, options, deferredData = [], deferredWatch = [], asMixin = false) { +function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) { const { // composition mixins, extends: extendsOptions, @@ -6306,18 +6330,18 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], // applyOptions is called non-as-mixin once per instance if (!asMixin) { isInBeforeCreate = true; - callSyncHook('beforeCreate', options, publicThis, globalMixins); + callSyncHook('beforeCreate', "bc" /* BEFORE_CREATE */, options, instance, globalMixins); isInBeforeCreate = false; // global mixins are applied first - applyMixins(instance, globalMixins, deferredData, deferredWatch); + applyMixins(instance, globalMixins, deferredData, deferredWatch, deferredProvide); } // extending a base component... if (extendsOptions) { - applyOptions(instance, extendsOptions, deferredData, deferredWatch, true); + applyOptions(instance, extendsOptions, deferredData, deferredWatch, deferredProvide, true); } // local mixins if (mixins) { - applyMixins(instance, mixins, deferredData, deferredWatch); + applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide); } const checkDuplicateProperties = (process.env.NODE_ENV !== 'production') ? createDuplicateChecker() : null; if ((process.env.NODE_ENV !== 'production')) { @@ -6445,12 +6469,17 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], }); } if (provideOptions) { - const provides = isFunction(provideOptions) - ? provideOptions.call(publicThis) - : provideOptions; - for (const key in provides) { - provide(key, provides[key]); - } + deferredProvide.push(provideOptions); + } + if (!asMixin && deferredProvide.length) { + deferredProvide.forEach(provideOptions => { + const provides = isFunction(provideOptions) + ? provideOptions.call(publicThis) + : provideOptions; + for (const key in provides) { + provide(key, provides[key]); + } + }); } // asset options. // To reduce memory usage, only components with mixins or extends will have @@ -6467,7 +6496,7 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } // lifecycle options if (!asMixin) { - callSyncHook('created', options, publicThis, globalMixins); + callSyncHook('created', "c" /* CREATED */, options, instance, globalMixins); } if (beforeMount) { onBeforeMount(beforeMount.bind(publicThis)); @@ -6509,44 +6538,44 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], onUnmounted(unmounted.bind(publicThis)); } } -function callSyncHook(name, options, ctx, globalMixins) { - callHookFromMixins(name, globalMixins, ctx); +function callSyncHook(name, type, options, instance, globalMixins) { + callHookFromMixins(name, type, globalMixins, instance); const { extends: base, mixins } = options; if (base) { - callHookFromExtends(name, base, ctx); + callHookFromExtends(name, type, base, instance); } if (mixins) { - callHookFromMixins(name, mixins, ctx); + callHookFromMixins(name, type, mixins, instance); } const selfHook = options[name]; if (selfHook) { - selfHook.call(ctx); + callWithAsyncErrorHandling(selfHook.bind(instance.proxy), instance, type); } } -function callHookFromExtends(name, base, ctx) { +function callHookFromExtends(name, type, base, instance) { if (base.extends) { - callHookFromExtends(name, base.extends, ctx); + callHookFromExtends(name, type, base.extends, instance); } const baseHook = base[name]; if (baseHook) { - baseHook.call(ctx); + callWithAsyncErrorHandling(baseHook.bind(instance.proxy), instance, type); } } -function callHookFromMixins(name, mixins, ctx) { +function callHookFromMixins(name, type, mixins, instance) { for (let i = 0; i < mixins.length; i++) { const chainedMixins = mixins[i].mixins; if (chainedMixins) { - callHookFromMixins(name, chainedMixins, ctx); + callHookFromMixins(name, type, chainedMixins, instance); } const fn = mixins[i][name]; if (fn) { - fn.call(ctx); + callWithAsyncErrorHandling(fn.bind(instance.proxy), instance, type); } } } -function applyMixins(instance, mixins, deferredData, deferredWatch) { +function applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide) { for (let i = 0; i < mixins.length; i++) { - applyOptions(instance, mixins[i], deferredData, deferredWatch, true); + applyOptions(instance, mixins[i], deferredData, deferredWatch, deferredProvide, true); } } function resolveData(instance, dataFn, publicThis) { @@ -6659,7 +6688,7 @@ const publicPropertiesMap = extend(Object.create(null), { $emit: i => i.emit, $options: i => (__VUE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type), $forceUpdate: i => () => queueJob(i.update), - $nextTick: () => nextTick, + $nextTick: i => nextTick.bind(i.proxy), $watch: i => (__VUE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP) }); const PublicInstanceProxyHandlers = { @@ -6669,6 +6698,10 @@ const PublicInstanceProxyHandlers = { if (key === "__v_skip" /* SKIP */) { return true; } + // for internal formatters to know that this is a Vue instance + if ((process.env.NODE_ENV !== 'production') && key === '__isVue') { + return true; + } // data / props / ctx // This getter gets called for every property access on the render context // during render and is a major hotspot. The most expensive part of this @@ -7016,7 +7049,7 @@ function setupStatefulComponent(instance, isSSR) { } } // 0. create render proxy property access cache - instance.accessCache = {}; + instance.accessCache = Object.create(null); // 1. create public instance / render proxy // also mark it raw so it's never observed instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers); @@ -7387,6 +7420,195 @@ const useSSRContext = () => { } }; +function initCustomFormatter() { + if (!(process.env.NODE_ENV !== 'production') || !true) { + return; + } + const vueStyle = { style: 'color:#3ba776' }; + const numberStyle = { style: 'color:#0b1bc9' }; + const stringStyle = { style: 'color:#b62e24' }; + const keywordStyle = { style: 'color:#9d288c' }; + // custom formatter for Chrome + // https://www.mattzeunert.com/2016/02/19/custom-chrome-devtools-object-formatters.html + const formatter = { + header(obj) { + // TODO also format ComponentPublicInstance & ctx.slots/attrs in setup + if (!isObject(obj)) { + return null; + } + if (obj.__isVue) { + return ['div', vueStyle, `VueInstance`]; + } + else if (isRef(obj)) { + return [ + 'div', + {}, + ['span', vueStyle, genRefFlag(obj)], + '<', + formatValue(obj.value), + `>` + ]; + } + else if (isReactive(obj)) { + return [ + 'div', + {}, + ['span', vueStyle, 'Reactive'], + '<', + formatValue(obj), + `>${isReadonly(obj) ? ` (readonly)` : ``}` + ]; + } + else if (isReadonly(obj)) { + return [ + 'div', + {}, + ['span', vueStyle, 'Readonly'], + '<', + formatValue(obj), + '>' + ]; + } + return null; + }, + hasBody(obj) { + return obj && obj.__isVue; + }, + body(obj) { + if (obj && obj.__isVue) { + return [ + 'div', + {}, + ...formatInstance(obj.$) + ]; + } + } + }; + function formatInstance(instance) { + const blocks = []; + if (instance.type.props && instance.props) { + blocks.push(createInstanceBlock('props', toRaw(instance.props))); + } + if (instance.setupState !== EMPTY_OBJ) { + blocks.push(createInstanceBlock('setup', instance.setupState)); + } + if (instance.data !== EMPTY_OBJ) { + blocks.push(createInstanceBlock('data', toRaw(instance.data))); + } + const computed = extractKeys(instance, 'computed'); + if (computed) { + blocks.push(createInstanceBlock('computed', computed)); + } + const injected = extractKeys(instance, 'inject'); + if (injected) { + blocks.push(createInstanceBlock('injected', injected)); + } + blocks.push([ + 'div', + {}, + [ + 'span', + { + style: keywordStyle.style + ';opacity:0.66' + }, + '$ (internal): ' + ], + ['object', { object: instance }] + ]); + return blocks; + } + function createInstanceBlock(type, target) { + target = extend({}, target); + if (!Object.keys(target).length) { + return ['span', {}]; + } + return [ + 'div', + { style: 'line-height:1.25em;margin-bottom:0.6em' }, + [ + 'div', + { + style: 'color:#476582' + }, + type + ], + [ + 'div', + { + style: 'padding-left:1.25em' + }, + ...Object.keys(target).map(key => { + return [ + 'div', + {}, + ['span', keywordStyle, key + ': '], + formatValue(target[key], false) + ]; + }) + ] + ]; + } + function formatValue(v, asRaw = true) { + if (typeof v === 'number') { + return ['span', numberStyle, v]; + } + else if (typeof v === 'string') { + return ['span', stringStyle, JSON.stringify(v)]; + } + else if (typeof v === 'boolean') { + return ['span', keywordStyle, v]; + } + else if (isObject(v)) { + return ['object', { object: asRaw ? toRaw(v) : v }]; + } + else { + return ['span', stringStyle, String(v)]; + } + } + function extractKeys(instance, type) { + const Comp = instance.type; + if (isFunction(Comp)) { + return; + } + const extracted = {}; + for (const key in instance.ctx) { + if (isKeyOfType(Comp, key, type)) { + extracted[key] = instance.ctx[key]; + } + } + return extracted; + } + function isKeyOfType(Comp, key, type) { + const opts = Comp[type]; + if ((isArray(opts) && opts.includes(key)) || + (isObject(opts) && key in opts)) { + return true; + } + if (Comp.extends && isKeyOfType(Comp.extends, key, type)) { + return true; + } + if (Comp.mixins && Comp.mixins.some(m => isKeyOfType(m, key, type))) { + return true; + } + } + function genRefFlag(v) { + if (v._shallow) { + return `ShallowRef`; + } + if (v.effect) { + return `ComputedRef`; + } + return `Ref`; + } + /* eslint-disable no-restricted-globals */ + if (window.devtoolsFormatters) { + window.devtoolsFormatters.push(formatter); + } + else { + window.devtoolsFormatters = [formatter]; + } +} + /** * Actual implementation */ @@ -7399,6 +7621,10 @@ function renderList(source, renderItem) { } } else if (typeof source === 'number') { + if ((process.env.NODE_ENV !== 'production') && !Number.isInteger(source)) { + warn(`The v-for range expect an integer value but got ${source}.`); + return []; + } ret = new Array(source); for (let i = 0; i < source; i++) { ret[i] = renderItem(i + 1, i); @@ -7434,7 +7660,7 @@ function toHandlers(obj) { return ret; } for (const key in obj) { - ret[`on${capitalize(key)}`] = obj[key]; + ret[toHandlerKey(key)] = obj[key]; } return ret; } @@ -7461,7 +7687,7 @@ function createSlots(slots, dynamicSlots) { } // Core API ------------------------------------------------------------------ -const version = "3.0.0"; +const version = "3.0.2"; /** * SSR utils for \@vue/server-renderer. Only exposed in cjs builds. * @internal @@ -7885,11 +8111,9 @@ function useCssVars(getter, scoped = false) { const prefix = scoped && instance.type.__scopeId ? `${instance.type.__scopeId.replace(/^data-v-/, '')}-` : ``; - onMounted(() => { - watchEffect(() => { - setVarsOnVNode(instance.subTree, getter(instance.proxy), prefix); - }); - }); + const setVars = () => setVarsOnVNode(instance.subTree, getter(instance.proxy), prefix); + onMounted(() => watchEffect(setVars)); + onUpdated(setVars); } function setVarsOnVNode(vnode, vars, prefix) { if ( vnode.shapeFlag & 128 /* SUSPENSE */) { @@ -8315,8 +8539,7 @@ function trigger$1(el, type) { // We are exporting the v-model runtime directly as vnode hooks so that it can // be tree-shaken in case v-model is never used. const vModelText = { - created(el, { value, modifiers: { lazy, trim, number } }, vnode) { - el.value = value == null ? '' : value; + created(el, { modifiers: { lazy, trim, number } }, vnode) { el._assign = getModelAssigner(vnode); const castToNumber = number || el.type === 'number'; addEventListener(el, lazy ? 'change' : 'input', e => { @@ -8346,8 +8569,15 @@ const vModelText = { addEventListener(el, 'change', onCompositionEnd); } }, + // set value on mounted so it's after min/max for type="range" + mounted(el, { value }) { + el.value = value == null ? '' : value; + }, beforeUpdate(el, { value, modifiers: { trim, number } }, vnode) { el._assign = getModelAssigner(vnode); + // avoid clearing unresolved text. #2302 + if (el.composing) + return; if (document.activeElement === el) { if (trim && el.value.trim() === value) { return; @@ -8384,13 +8614,11 @@ const vModelCheckbox = { } } else if (isSet(modelValue)) { - const found = modelValue.has(elementValue); - if (checked && !found) { - assign(modelValue.add(elementValue)); + if (checked) { + modelValue.add(elementValue); } - else if (!checked && found) { + else { modelValue.delete(elementValue); - assign(modelValue); } } else { @@ -8409,7 +8637,7 @@ function setChecked(el, { value, oldValue }, vnode) { el.checked = looseIndexOf(value, vnode.props.value) > -1; } else if (isSet(value)) { - el.checked = looseHas(value, vnode.props.value); + el.checked = value.has(vnode.props.value); } else if (value !== oldValue) { el.checked = looseEqual(value, getCheckboxValue(el, true)); @@ -8431,11 +8659,11 @@ const vModelRadio = { } }; const vModelSelect = { - created(el, binding, vnode) { + created(el, { modifiers: { number } }, vnode) { addEventListener(el, 'change', () => { const selectedVal = Array.prototype.filter .call(el.options, (o) => o.selected) - .map(getValue); + .map((o) => number ? toNumber(getValue(o)) : getValue(o)); el._assign(el.multiple ? selectedVal : selectedVal[0]); }); el._assign = getModelAssigner(vnode); @@ -8468,7 +8696,7 @@ function setSelected(el, value) { option.selected = looseIndexOf(value, optionValue) > -1; } else { - option.selected = looseHas(value, optionValue); + option.selected = value.has(optionValue); } } else { @@ -8712,6 +8940,7 @@ function initDev() { { console.info(`You are running a development build of Vue.\n` + `Make sure to use the production build (*.prod.js) when deploying for production.`); + initCustomFormatter(); } } @@ -8725,4 +8954,4 @@ const compile$1 = () => { } }; -export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, customRef, defineAsyncComponent, defineComponent, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isVNode, markRaw, mergeProps, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId }; +export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, customRef, defineAsyncComponent, defineComponent, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isVNode, markRaw, mergeProps, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId }; diff --git a/packages/uni-h5/dist/uni-h5.esm.js b/packages/uni-h5/dist/uni-h5.esm.js index 506610fb4..cafbfe471 100644 --- a/packages/uni-h5/dist/uni-h5.esm.js +++ b/packages/uni-h5/dist/uni-h5.esm.js @@ -1544,6 +1544,192 @@ const canIUse = /* @__PURE__ */ createApi({type: API_TYPE_SYNC, name: "canIUse"} const makePhoneCall = /* @__PURE__ */ createApi({type: API_TYPE_ASYNC, name: "makePhoneCall"}, (option) => { window.location.href = `tel:${option.phoneNumber}`; }, MakePhoneCallProtocol); +var attrs$1 = ["top", "left", "right", "bottom"]; +var inited$1; +var elementComputedStyle$1 = {}; +var support$1; +function getSupport$1() { + if (!("CSS" in window) || typeof CSS.supports != "function") { + support$1 = ""; + } else if (CSS.supports("top: env(safe-area-inset-top)")) { + support$1 = "env"; + } else if (CSS.supports("top: constant(safe-area-inset-top)")) { + support$1 = "constant"; + } else { + support$1 = ""; + } + return support$1; +} +function init$1() { + support$1 = typeof support$1 === "string" ? support$1 : getSupport$1(); + if (!support$1) { + attrs$1.forEach(function(attr) { + elementComputedStyle$1[attr] = 0; + }); + return; + } + function setStyle(el, style) { + var elStyle = el.style; + Object.keys(style).forEach(function(key) { + var val = style[key]; + elStyle[key] = val; + }); + } + var cbs = []; + function parentReady(callback) { + if (callback) { + cbs.push(callback); + } else { + cbs.forEach(function(cb) { + cb(); + }); + } + } + var passiveEvents = false; + try { + var opts = Object.defineProperty({}, "passive", { + get: function() { + passiveEvents = {passive: true}; + } + }); + window.addEventListener("test", null, opts); + } catch (e) { + } + function addChild(parent, attr) { + var a1 = document.createElement("div"); + var a2 = document.createElement("div"); + var a1Children = document.createElement("div"); + var a2Children = document.createElement("div"); + var W = 100; + var MAX = 1e4; + var aStyle = { + position: "absolute", + width: W + "px", + height: "200px", + boxSizing: "border-box", + overflow: "hidden", + paddingBottom: support$1 + "(safe-area-inset-" + attr + ")" + }; + setStyle(a1, aStyle); + setStyle(a2, aStyle); + setStyle(a1Children, { + transition: "0s", + animation: "none", + width: "400px", + height: "400px" + }); + setStyle(a2Children, { + transition: "0s", + animation: "none", + width: "250%", + height: "250%" + }); + a1.appendChild(a1Children); + a2.appendChild(a2Children); + parent.appendChild(a1); + parent.appendChild(a2); + parentReady(function() { + a1.scrollTop = a2.scrollTop = MAX; + var a1LastScrollTop = a1.scrollTop; + var a2LastScrollTop = a2.scrollTop; + function onScroll() { + if (this.scrollTop === (this === a1 ? a1LastScrollTop : a2LastScrollTop)) { + return; + } + a1.scrollTop = a2.scrollTop = MAX; + a1LastScrollTop = a1.scrollTop; + a2LastScrollTop = a2.scrollTop; + attrChange$1(attr); + } + a1.addEventListener("scroll", onScroll, passiveEvents); + a2.addEventListener("scroll", onScroll, passiveEvents); + }); + var computedStyle = getComputedStyle(a1); + Object.defineProperty(elementComputedStyle$1, attr, { + configurable: true, + get: function() { + return parseFloat(computedStyle.paddingBottom); + } + }); + } + var parentDiv = document.createElement("div"); + setStyle(parentDiv, { + position: "absolute", + left: "0", + top: "0", + width: "0", + height: "0", + zIndex: "-1", + overflow: "hidden", + visibility: "hidden" + }); + attrs$1.forEach(function(key) { + addChild(parentDiv, key); + }); + document.body.appendChild(parentDiv); + parentReady(); + inited$1 = true; +} +function getAttr$1(attr) { + if (!inited$1) { + init$1(); + } + return elementComputedStyle$1[attr]; +} +var changeAttrs$1 = []; +function attrChange$1(attr) { + if (!changeAttrs$1.length) { + setTimeout(function() { + var style = {}; + changeAttrs$1.forEach(function(attr2) { + style[attr2] = elementComputedStyle$1[attr2]; + }); + changeAttrs$1.length = 0; + callbacks$1.forEach(function(callback) { + callback(style); + }); + }, 0); + } + changeAttrs$1.push(attr); +} +var callbacks$1 = []; +function onChange$1(callback) { + if (!getSupport$1()) { + return; + } + if (!inited$1) { + init$1(); + } + if (typeof callback === "function") { + callbacks$1.push(callback); + } +} +function offChange$1(callback) { + var index2 = callbacks$1.indexOf(callback); + if (index2 >= 0) { + callbacks$1.splice(index2, 1); + } +} +var safeAreaInsets$1 = { + get support() { + return (typeof support$1 === "string" ? support$1 : getSupport$1()).length != 0; + }, + get top() { + return getAttr$1("top"); + }, + get left() { + return getAttr$1("left"); + }, + get right() { + return getAttr$1("right"); + }, + get bottom() { + return getAttr$1("bottom"); + }, + onChange: onChange$1, + offChange: offChange$1 +}; +var out$1 = safeAreaInsets$1; const ua = navigator.userAgent; const isAndroid = /android/i.test(ua); const isIOS$1 = /iphone|ipad|ipod/i.test(ua); @@ -1557,7 +1743,7 @@ const getSystemInfoSync = /* @__PURE__ */ createApi({type: API_TYPE_SYNC}, () => var windowWidth = Math.min(window.innerWidth, document.documentElement.clientWidth, screenWidth) || screenWidth; var windowHeight = window.innerHeight; var language = navigator.language; - var statusBarHeight = out.top; + var statusBarHeight = out$1.top; var osname; var osversion; var model; @@ -1616,12 +1802,12 @@ const getSystemInfoSync = /* @__PURE__ */ createApi({type: API_TYPE_SYNC}, () => var system = `${osname} ${osversion}`; var platform = osname.toLocaleLowerCase(); var safeArea = { - left: out.left, - right: windowWidth - out.right, - top: out.top, - bottom: windowHeight - out.bottom, - width: windowWidth - out.left - out.right, - height: windowHeight - out.top - out.bottom + left: out$1.left, + right: windowWidth - out$1.right, + top: out$1.top, + bottom: windowHeight - out$1.bottom, + width: windowWidth - out$1.left - out$1.right, + height: windowHeight - out$1.top - out$1.bottom }; const {top: windowTop, bottom: windowBottom} = getWindowOffset(); windowHeight -= windowTop; @@ -1641,10 +1827,10 @@ const getSystemInfoSync = /* @__PURE__ */ createApi({type: API_TYPE_SYNC}, () => model, safeArea, safeAreaInsets: { - top: out.top, - right: out.right, - bottom: out.bottom, - left: out.left + top: out$1.top, + right: out$1.right, + bottom: out$1.bottom, + left: out$1.left } }; }); @@ -2763,7 +2949,7 @@ var script$8 = { }, this.pullToRefresh); let offset = uni.upx2px(refreshOptions.offset); if (titleNView.type !== "none" && titleNView.type !== "transparent") { - offset += NAVBAR_HEIGHT + out.top; + offset += NAVBAR_HEIGHT + out$1.top; } refreshOptions.offset = offset; refreshOptions.height = uni.upx2px(refreshOptions.height); diff --git a/packages/uni-mp-alipay/dist/uni.api.esm.js b/packages/uni-mp-alipay/dist/uni.api.esm.js index 28f3b6713..78a3a3715 100644 --- a/packages/uni-mp-alipay/dist/uni.api.esm.js +++ b/packages/uni-mp-alipay/dist/uni.api.esm.js @@ -450,19 +450,7 @@ function addSafeAreaInsets(fromRes, toRes) { }; } } -const redirectTo = {}; -const createCanvasContext = { - returnValue(fromRes, toRes) { - const measureText = fromRes.measureText; - toRes.measureText = function (text, callback) { - const textMetrics = measureText.call(this, text); - if (typeof callback === 'function') { - setTimeout(() => callback(textMetrics), 0); - } - return textMetrics; - }; - } -}; +const redirectTo = {}; const getProvider = initGetProvider({ oauth: ['alipay'], @@ -1050,8 +1038,7 @@ var protocols = /*#__PURE__*/Object.freeze({ saveImageToPhotosAlbum: saveImageToPhotosAlbum, saveVideoToPhotosAlbum: saveVideoToPhotosAlbum, chooseAddress: chooseAddress, - redirectTo: redirectTo, - createCanvasContext: createCanvasContext + redirectTo: redirectTo }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-baidu/dist/uni.api.esm.js b/packages/uni-mp-baidu/dist/uni.api.esm.js index 5801e1d58..5b5a1dc57 100644 --- a/packages/uni-mp-baidu/dist/uni.api.esm.js +++ b/packages/uni-mp-baidu/dist/uni.api.esm.js @@ -487,19 +487,7 @@ const getSystemInfo = { returnValue: addSafeAreaInsets }; const getSystemInfoSync = getSystemInfo; -const redirectTo = {}; -const createCanvasContext = { - returnValue(fromRes, toRes) { - const measureText = fromRes.measureText; - toRes.measureText = function (text, callback) { - const textMetrics = measureText.call(this, text); - if (typeof callback === 'function') { - setTimeout(() => callback(textMetrics), 0); - } - return textMetrics; - }; - } -}; +const redirectTo = {}; const getProvider = initGetProvider({ oauth: ['baidu'], @@ -617,8 +605,7 @@ var protocols = /*#__PURE__*/Object.freeze({ redirectTo: redirectTo, previewImage: previewImage, getSystemInfo: getSystemInfo, - getSystemInfoSync: getSystemInfoSync, - createCanvasContext: createCanvasContext + getSystemInfoSync: getSystemInfoSync }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-qq/dist/uni.api.esm.js b/packages/uni-mp-qq/dist/uni.api.esm.js index ef851c825..e733ecaf5 100644 --- a/packages/uni-mp-qq/dist/uni.api.esm.js +++ b/packages/uni-mp-qq/dist/uni.api.esm.js @@ -487,19 +487,7 @@ const getSystemInfo = { returnValue: addSafeAreaInsets }; const getSystemInfoSync = getSystemInfo; -const redirectTo = {}; -const createCanvasContext = { - returnValue(fromRes, toRes) { - const measureText = fromRes.measureText; - toRes.measureText = function (text, callback) { - const textMetrics = measureText.call(this, text); - if (typeof callback === 'function') { - setTimeout(() => callback(textMetrics), 0); - } - return textMetrics; - }; - } -}; +const redirectTo = {}; const getProvider = initGetProvider({ oauth: ['qq'], @@ -518,8 +506,7 @@ var protocols = /*#__PURE__*/Object.freeze({ redirectTo: redirectTo, previewImage: previewImage, getSystemInfo: getSystemInfo, - getSystemInfoSync: getSystemInfoSync, - createCanvasContext: createCanvasContext + getSystemInfoSync: getSystemInfoSync }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-toutiao/dist/uni.api.esm.js b/packages/uni-mp-toutiao/dist/uni.api.esm.js index 9d0ce5b12..fb3735dd5 100644 --- a/packages/uni-mp-toutiao/dist/uni.api.esm.js +++ b/packages/uni-mp-toutiao/dist/uni.api.esm.js @@ -472,19 +472,7 @@ const previewImage = { }; } }; -const redirectTo = {}; -const createCanvasContext = { - returnValue(fromRes, toRes) { - const measureText = fromRes.measureText; - toRes.measureText = function (text, callback) { - const textMetrics = measureText.call(this, text); - if (typeof callback === 'function') { - setTimeout(() => callback(textMetrics), 0); - } - return textMetrics; - }; - } -}; +const redirectTo = {}; const getProvider = initGetProvider({ oauth: ['toutiao'], @@ -586,8 +574,7 @@ var protocols = /*#__PURE__*/Object.freeze({ requestPayment: requestPayment, getFileInfo: getFileInfo, redirectTo: redirectTo, - previewImage: previewImage, - createCanvasContext: createCanvasContext + previewImage: previewImage }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-vue/dist/vue.runtime.esm.js b/packages/uni-mp-vue/dist/vue.runtime.esm.js index 0846d821b..ea915ea55 100644 --- a/packages/uni-mp-vue/dist/vue.runtime.esm.js +++ b/packages/uni-mp-vue/dist/vue.runtime.esm.js @@ -1,4 +1,4 @@ -import { isSymbol, extend, isMap, isObject, toRawType, def, isArray, isString, isFunction, isPromise, capitalize, remove, EMPTY_OBJ, NOOP, isGloballyWhitelisted, isIntegerKey, hasOwn, hasChanged, NO, invokeArrayFns, isSet, makeMap, hyphenate, isReservedProp, camelize, EMPTY_ARR, toTypeString, isOn } from '@vue/shared'; +import { isSymbol, extend, isMap, isObject, toRawType, def, isArray, isString, isFunction, isPromise, toHandlerKey, remove, EMPTY_OBJ, NOOP, isGloballyWhitelisted, isIntegerKey, hasOwn, hasChanged, capitalize, NO, invokeArrayFns, isSet, makeMap, toNumber, hyphenate, camelize, isReservedProp, EMPTY_ARR, toTypeString, isOn } from '@vue/shared'; export { camelize } from '@vue/shared'; const targetMap = new WeakMap(); @@ -50,6 +50,7 @@ function createReactiveEffect(fn, options) { } }; effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; effect._isEffect = true; effect.active = true; effect.raw = fn; @@ -115,7 +116,7 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) { const add = (effectsToAdd) => { if (effectsToAdd) { effectsToAdd.forEach(effect => { - if (effect !== activeEffect || effect.options.allowRecurse) { + if (effect !== activeEffect || effect.allowRecurse) { effects.add(effect); } }); @@ -220,7 +221,7 @@ const arrayInstrumentations = {}; arrayInstrumentations[key] = function (...args) { pauseTracking(); const res = method.apply(this, args); - enableTracking(); + resetTracking(); return res; }; }); @@ -241,8 +242,7 @@ function createGetter(isReadonly = false, shallow = false) { return Reflect.get(arrayInstrumentations, key, receiver); } const res = Reflect.get(target, key, receiver); - const keyIsSymbol = isSymbol(key); - if (keyIsSymbol + if (isSymbol(key) ? builtInSymbols.has(key) : key === `__proto__` || key === `__v_isRef`) { return res; @@ -312,7 +312,7 @@ function has(target, key) { return result; } function ownKeys(target) { - track(target, "iterate" /* ITERATE */, ITERATE_KEY); + track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY); return Reflect.ownKeys(target); } const mutableHandlers = { @@ -595,7 +595,7 @@ function checkIdentityKeys(target, has, key) { if (rawKey !== key && has.call(target, rawKey)) { const type = toRawType(target); console.warn(`Reactive ${type} contains both the raw and reactive ` + - `versions of the same object${type === `Map` ? `as keys` : ``}, ` + + `versions of the same object${type === `Map` ? ` as keys` : ``}, ` + `which can lead to inconsistencies. ` + `Avoid differentiating between the raw and reactive versions ` + `of an object and only use the reactive version if possible.`); @@ -730,7 +730,7 @@ function createRef(rawValue, shallow = false) { return new RefImpl(rawValue, shallow); } function triggerRef(ref) { - trigger(ref, "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); + trigger(toRaw(ref), "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); } function unref(ref) { return isRef(ref) ? ref.value : ref; @@ -1028,7 +1028,7 @@ function handleError(err, instance, type, throwInDev = true) { const errorCapturedHooks = cur.ec; if (errorCapturedHooks) { for (let i = 0; i < errorCapturedHooks.length; i++) { - if (errorCapturedHooks[i](err, exposedInstance, errorInfo)) { + if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) { return; } } @@ -1086,7 +1086,7 @@ let currentPreFlushParentJob = null; const RECURSION_LIMIT = 100; function nextTick(fn) { const p = currentFlushPromise || resolvedPromise; - return fn ? p.then(fn) : p; + return fn ? p.then(this ? fn.bind(this) : fn) : p; } function queueJob(job) { // the dedupe search uses the startIndex argument of Array.includes() @@ -1235,21 +1235,21 @@ function checkRecursiveUpdates(seen, fn) { } } -function emit(instance, event, ...args) { +function emit(instance, event, ...rawArgs) { const props = instance.vnode.props || EMPTY_OBJ; if ((process.env.NODE_ENV !== 'production')) { const { emitsOptions, propsOptions: [propsOptions] } = instance; if (emitsOptions) { if (!(event in emitsOptions)) { - if (!propsOptions || !(`on` + capitalize(event) in propsOptions)) { + if (!propsOptions || !(toHandlerKey(event) in propsOptions)) { warn(`Component emitted event "${event}" but it is neither declared in ` + - `the emits option nor as an "on${capitalize(event)}" prop.`); + `the emits option nor as an "${toHandlerKey(event)}" prop.`); } } else { const validator = emitsOptions[event]; if (isFunction(validator)) { - const isValid = validator(...args); + const isValid = validator(...rawArgs); if (!isValid) { warn(`Invalid event arguments: event validation failed for event "${event}".`); } @@ -1257,34 +1257,57 @@ function emit(instance, event, ...args) { } } } + let args = rawArgs; + const isModelListener = event.startsWith('update:'); + // for v-model update:xxx events, apply modifiers on args + const modelArg = isModelListener && event.slice(7); + if (modelArg && modelArg in props) { + const modifiersKey = `${modelArg === 'modelValue' ? 'model' : modelArg}Modifiers`; + const { number, trim } = props[modifiersKey] || EMPTY_OBJ; + if (trim) { + args = rawArgs.map(a => a.trim()); + } + else if (number) { + args = rawArgs.map(toNumber); + } + } if ((process.env.NODE_ENV !== 'production') || false) ; - let handlerName = `on${capitalize(event)}`; + if ((process.env.NODE_ENV !== 'production')) { + const lowerCaseEvent = event.toLowerCase(); + if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) { + warn(`Event "${lowerCaseEvent}" is emitted in component ` + + `${formatComponentName(instance, instance.type)} but the handler is registered for "${event}". ` + + `Note that HTML attributes are case-insensitive and you cannot use ` + + `v-on to listen to camelCase events when using in-DOM templates. ` + + `You should probably use "${hyphenate(event)}" instead of "${event}".`); + } + } + // convert handler name to camelCase. See issue #2249 + let handlerName = toHandlerKey(camelize(event)); let handler = props[handlerName]; // for v-model update:xxx events, also trigger kebab-case equivalent // for props passed via kebab-case - if (!handler && event.startsWith('update:')) { - handlerName = `on${capitalize(hyphenate(event))}`; + if (!handler && isModelListener) { + handlerName = toHandlerKey(hyphenate(event)); handler = props[handlerName]; } - if (!handler) { - handler = props[handlerName + `Once`]; + if (handler) { + callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); + } + const onceHandler = props[handlerName + `Once`]; + if (onceHandler) { if (!instance.emitted) { (instance.emitted = {})[handlerName] = true; } else if (instance.emitted[handlerName]) { return; } - } - if (handler) { - callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); + callWithAsyncErrorHandling(onceHandler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { - const appId = appContext.app ? appContext.app._uid : -1; - const cache = comp.__emits || (comp.__emits = {}); - const cached = cache[appId]; - if (cached !== undefined) { - return cached; + if (!appContext.deopt && comp.__emits !== undefined) { + return comp.__emits; } const raw = comp.emits; let normalized = {}; @@ -1306,7 +1329,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (cache[appId] = null); + return (comp.__emits = null); } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -1314,7 +1337,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { else { extend(normalized, raw); } - return (cache[appId] = normalized); + return (comp.__emits = normalized); } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are @@ -1422,11 +1445,8 @@ function resolvePropValue(options, props, key, value, instance) { return value; } function normalizePropsOptions(comp, appContext, asMixin = false) { - const appId = appContext.app ? appContext.app._uid : -1; - const cache = comp.__props || (comp.__props = {}); - const cached = cache[appId]; - if (cached) { - return cached; + if (!appContext.deopt && comp.__props) { + return comp.__props; } const raw = comp.props; const normalized = {}; @@ -1452,7 +1472,7 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (cache[appId] = EMPTY_ARR); + return (comp.__props = EMPTY_ARR); } if (isArray(raw)) { for (let i = 0; i < raw.length; i++) { @@ -1489,7 +1509,16 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } } - return (cache[appId] = [normalized, needCastKeys]); + return (comp.__props = [normalized, needCastKeys]); +} +function validatePropName(key) { + if (key[0] !== '$') { + return true; + } + else if ((process.env.NODE_ENV !== 'production')) { + warn(`Invalid prop name: "${key}" is a reserved property.`); + } + return false; } // use function string name to check type constructors // so that it works across vms / iframes. @@ -1526,18 +1555,6 @@ function validateProps(props, instance) { validateProp(key, rawValues[key], opt, !hasOwn(rawValues, key)); } } -/** - * dev only - */ -function validatePropName(key) { - if (key[0] !== '$') { - return true; - } - else if ((process.env.NODE_ENV !== 'production')) { - warn(`Invalid prop name: "${key}" is a reserved property.`); - } - return false; -} /** * dev only */ @@ -1685,7 +1702,7 @@ function injectHook(type, hook, target = currentInstance, prepend = false) { return wrappedHook; } else if ((process.env.NODE_ENV !== 'production')) { - const apiName = `on${capitalize(ErrorTypeStrings[type].replace(/ hook$/, ''))}`; + const apiName = toHandlerKey(ErrorTypeStrings[type].replace(/ hook$/, '')); warn(`${apiName} is called when there is no active component instance to be ` + `associated with. ` + `Lifecycle injection APIs can only be used during execution of setup().` + @@ -1841,6 +1858,11 @@ function createAppAPI() { if (__VUE_OPTIONS_API__) { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin); + // global mixin with props/emits de-optimizes props/emits + // normalization caching. + if (mixin.props || mixin.emits) { + context.deopt = true; + } } else if ((process.env.NODE_ENV !== 'production')) { warn('Mixin has already been applied to target app' + @@ -1930,9 +1952,10 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM `a reactive object, or an array of these types.`); }; let getter; - const isRefSource = isRef(source); - if (isRefSource) { + let forceTrigger = false; + if (isRef(source)) { getter = () => source.value; + forceTrigger = !!source._shallow; } else if (isReactive(source)) { getter = () => source; @@ -1994,7 +2017,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM if (cb) { // watch(source, cb) const newValue = runner(); - if (deep || isRefSource || hasChanged(newValue, oldValue)) { + if (deep || forceTrigger || hasChanged(newValue, oldValue)) { // cleanup before running cb again if (cleanup) { cleanup(); @@ -2013,7 +2036,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM runner(); } }; - // important: mark the job as a watcher callback so that scheduler knows it + // important: mark the job as a watcher callback so that scheduler knows // it is allowed to self-trigger (#1727) job.allowRecurse = !!cb; let scheduler; @@ -2086,14 +2109,8 @@ function traverse(value, seen = new Set()) { traverse(value[i], seen); } } - else if (isMap(value)) { - value.forEach((_, key) => { - // to register mutation dep for existing keys - traverse(value.get(key), seen); - }); - } - else if (isSet(value)) { - value.forEach(v => { + else if (isSet(value) || isMap(value)) { + value.forEach((v) => { traverse(v, seen); }); } @@ -2131,8 +2148,13 @@ function inject(key, defaultValue, treatDefaultAsFactory = false) { // a functional component const instance = currentInstance || currentRenderingInstance; if (instance) { - const provides = instance.provides; - if (key in provides) { + // #2400 + // to support `app.use` plugins, + // fallback to appContext's `provides` if the intance is at root + const provides = instance.parent == null + ? instance.vnode.appContext && instance.vnode.appContext.provides + : instance.parent.provides; + if (provides && key in provides) { // TS doesn't allow symbol as index type return provides[key]; } @@ -2162,7 +2184,7 @@ function createDuplicateChecker() { }; } let isInBeforeCreate = false; -function applyOptions(instance, options, deferredData = [], deferredWatch = [], asMixin = false) { +function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) { const { // composition mixins, extends: extendsOptions, @@ -2181,18 +2203,18 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], // applyOptions is called non-as-mixin once per instance if (!asMixin) { isInBeforeCreate = true; - callSyncHook('beforeCreate', options, publicThis, globalMixins); + callSyncHook('beforeCreate', "bc" /* BEFORE_CREATE */, options, instance, globalMixins); isInBeforeCreate = false; // global mixins are applied first - applyMixins(instance, globalMixins, deferredData, deferredWatch); + applyMixins(instance, globalMixins, deferredData, deferredWatch, deferredProvide); } // extending a base component... if (extendsOptions) { - applyOptions(instance, extendsOptions, deferredData, deferredWatch, true); + applyOptions(instance, extendsOptions, deferredData, deferredWatch, deferredProvide, true); } // local mixins if (mixins) { - applyMixins(instance, mixins, deferredData, deferredWatch); + applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide); } const checkDuplicateProperties = (process.env.NODE_ENV !== 'production') ? createDuplicateChecker() : null; if ((process.env.NODE_ENV !== 'production')) { @@ -2321,12 +2343,19 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], }); } // fixed by xxxxxx - if (!__VUE_CREATED_DEFERRED__ && provideOptions) { - const provides = isFunction(provideOptions) - ? provideOptions.call(publicThis) - : provideOptions; - for (const key in provides) { - provide(key, provides[key]); + if (!__VUE_CREATED_DEFERRED__) { + if (provideOptions) { + deferredProvide.push(provideOptions); + } + if (!asMixin && deferredProvide.length) { + deferredProvide.forEach(provideOptions => { + const provides = isFunction(provideOptions) + ? provideOptions.call(publicThis) + : provideOptions; + for (const key in provides) { + provide(key, provides[key]); + } + }); } } // asset options. @@ -2346,11 +2375,11 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], // lifecycle options if (__VUE_CREATED_DEFERRED__) { ctx.$callSyncHook = function (name) { - return callSyncHook(name, options, publicThis, globalMixins); + return callSyncHook(name, "c" /* CREATED */, options, instance, globalMixins); }; } else if (!asMixin) { - callSyncHook('created', options, publicThis, globalMixins); + callSyncHook('created', "c" /* CREATED */, options, instance, globalMixins); } if (beforeMount) { onBeforeMount(beforeMount.bind(publicThis)); @@ -2396,44 +2425,44 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], instance.ctx.$onApplyOptions(options, instance, publicThis); } } -function callSyncHook(name, options, ctx, globalMixins) { - callHookFromMixins(name, globalMixins, ctx); +function callSyncHook(name, type, options, instance, globalMixins) { + callHookFromMixins(name, type, globalMixins, instance); const { extends: base, mixins } = options; if (base) { - callHookFromExtends(name, base, ctx); + callHookFromExtends(name, type, base, instance); } if (mixins) { - callHookFromMixins(name, mixins, ctx); + callHookFromMixins(name, type, mixins, instance); } const selfHook = options[name]; if (selfHook) { - selfHook.call(ctx); + callWithAsyncErrorHandling(selfHook.bind(instance.proxy), instance, type); } } -function callHookFromExtends(name, base, ctx) { +function callHookFromExtends(name, type, base, instance) { if (base.extends) { - callHookFromExtends(name, base.extends, ctx); + callHookFromExtends(name, type, base.extends, instance); } const baseHook = base[name]; if (baseHook) { - baseHook.call(ctx); + callWithAsyncErrorHandling(baseHook.bind(instance.proxy), instance, type); } } -function callHookFromMixins(name, mixins, ctx) { +function callHookFromMixins(name, type, mixins, instance) { for (let i = 0; i < mixins.length; i++) { const chainedMixins = mixins[i].mixins; if (chainedMixins) { - callHookFromMixins(name, chainedMixins, ctx); + callHookFromMixins(name, type, chainedMixins, instance); } const fn = mixins[i][name]; if (fn) { - fn.call(ctx); + callWithAsyncErrorHandling(fn.bind(instance.proxy), instance, type); } } } -function applyMixins(instance, mixins, deferredData, deferredWatch) { +function applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide) { for (let i = 0; i < mixins.length; i++) { - applyOptions(instance, mixins[i], deferredData, deferredWatch, true); + applyOptions(instance, mixins[i], deferredData, deferredWatch, deferredProvide, true); } } function resolveData(instance, dataFn, publicThis) { @@ -2546,7 +2575,7 @@ const publicPropertiesMap = extend(Object.create(null), { $emit: i => i.emit, $options: i => (__VUE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type), $forceUpdate: i => () => queueJob(i.update), - // $nextTick: () => nextTick, // fixed by xxxxxx + // $nextTick: i => nextTick.bind(i.proxy!), // fixed by xxxxxx $watch: i => (__VUE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP) }); const PublicInstanceProxyHandlers = { @@ -2556,6 +2585,10 @@ const PublicInstanceProxyHandlers = { if (key === "__v_skip" /* SKIP */) { return true; } + // for internal formatters to know that this is a Vue instance + if ((process.env.NODE_ENV !== 'production') && key === '__isVue') { + return true; + } // data / props / ctx // This getter gets called for every property access on the render context // during render and is a major hotspot. The most expensive part of this @@ -2900,7 +2933,7 @@ function setupStatefulComponent(instance, isSSR) { } } // 0. create render proxy property access cache - instance.accessCache = {}; + instance.accessCache = Object.create(null); // 1. create public instance / render proxy // also mark it raw so it's never observed instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers); @@ -3077,7 +3110,7 @@ function computed$1(getterOrOptions) { } // Core API ------------------------------------------------------------------ -const version = "3.0.0"; +const version = "3.0.2"; // import deepCopy from './deepCopy' /** diff --git a/packages/uni-mp-vue/lib/vue.runtime.esm.js b/packages/uni-mp-vue/lib/vue.runtime.esm.js index c7eeec758..39c99a2a6 100644 --- a/packages/uni-mp-vue/lib/vue.runtime.esm.js +++ b/packages/uni-mp-vue/lib/vue.runtime.esm.js @@ -1,4 +1,4 @@ -import { EMPTY_OBJ, isArray, isMap, isIntegerKey, isSymbol, extend, hasOwn, isObject, hasChanged, capitalize, toRawType, def, isFunction, NOOP, isString, isPromise, hyphenate, isOn, isReservedProp, camelize, EMPTY_ARR, makeMap, remove, NO, isSet, isGloballyWhitelisted, toTypeString, invokeArrayFns } from '@vue/shared'; +import { EMPTY_OBJ, isArray, isMap, isIntegerKey, isSymbol, extend, hasOwn, isObject, hasChanged, capitalize, toRawType, def, isFunction, NOOP, isString, isPromise, toHandlerKey, toNumber, hyphenate, camelize, isOn, isReservedProp, EMPTY_ARR, makeMap, remove, NO, isSet, isGloballyWhitelisted, toTypeString, invokeArrayFns } from '@vue/shared'; export { camelize } from '@vue/shared'; const targetMap = new WeakMap(); @@ -50,6 +50,7 @@ function createReactiveEffect(fn, options) { } }; effect.id = uid++; + effect.allowRecurse = !!options.allowRecurse; effect._isEffect = true; effect.active = true; effect.raw = fn; @@ -115,7 +116,7 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) { const add = (effectsToAdd) => { if (effectsToAdd) { effectsToAdd.forEach(effect => { - if (effect !== activeEffect || effect.options.allowRecurse) { + if (effect !== activeEffect || effect.allowRecurse) { effects.add(effect); } }); @@ -220,7 +221,7 @@ const arrayInstrumentations = {}; arrayInstrumentations[key] = function (...args) { pauseTracking(); const res = method.apply(this, args); - enableTracking(); + resetTracking(); return res; }; }); @@ -241,8 +242,7 @@ function createGetter(isReadonly = false, shallow = false) { return Reflect.get(arrayInstrumentations, key, receiver); } const res = Reflect.get(target, key, receiver); - const keyIsSymbol = isSymbol(key); - if (keyIsSymbol + if (isSymbol(key) ? builtInSymbols.has(key) : key === `__proto__` || key === `__v_isRef`) { return res; @@ -312,7 +312,7 @@ function has(target, key) { return result; } function ownKeys(target) { - track(target, "iterate" /* ITERATE */, ITERATE_KEY); + track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY); return Reflect.ownKeys(target); } const mutableHandlers = { @@ -595,7 +595,7 @@ function checkIdentityKeys(target, has, key) { if (rawKey !== key && has.call(target, rawKey)) { const type = toRawType(target); console.warn(`Reactive ${type} contains both the raw and reactive ` + - `versions of the same object${type === `Map` ? `as keys` : ``}, ` + + `versions of the same object${type === `Map` ? ` as keys` : ``}, ` + `which can lead to inconsistencies. ` + `Avoid differentiating between the raw and reactive versions ` + `of an object and only use the reactive version if possible.`); @@ -730,7 +730,7 @@ function createRef(rawValue, shallow = false) { return new RefImpl(rawValue, shallow); } function triggerRef(ref) { - trigger(ref, "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); + trigger(toRaw(ref), "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); } function unref(ref) { return isRef(ref) ? ref.value : ref; @@ -1028,7 +1028,7 @@ function handleError(err, instance, type, throwInDev = true) { const errorCapturedHooks = cur.ec; if (errorCapturedHooks) { for (let i = 0; i < errorCapturedHooks.length; i++) { - if (errorCapturedHooks[i](err, exposedInstance, errorInfo)) { + if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) { return; } } @@ -1086,7 +1086,7 @@ let currentPreFlushParentJob = null; const RECURSION_LIMIT = 100; function nextTick(fn) { const p = currentFlushPromise || resolvedPromise; - return fn ? p.then(fn) : p; + return fn ? p.then(this ? fn.bind(this) : fn) : p; } function queueJob(job) { // the dedupe search uses the startIndex argument of Array.includes() @@ -1235,21 +1235,21 @@ function checkRecursiveUpdates(seen, fn) { } } -function emit(instance, event, ...args) { +function emit(instance, event, ...rawArgs) { const props = instance.vnode.props || EMPTY_OBJ; if ((process.env.NODE_ENV !== 'production')) { const { emitsOptions, propsOptions: [propsOptions] } = instance; if (emitsOptions) { if (!(event in emitsOptions)) { - if (!propsOptions || !(`on` + capitalize(event) in propsOptions)) { + if (!propsOptions || !(toHandlerKey(event) in propsOptions)) { warn(`Component emitted event "${event}" but it is neither declared in ` + - `the emits option nor as an "on${capitalize(event)}" prop.`); + `the emits option nor as an "${toHandlerKey(event)}" prop.`); } } else { const validator = emitsOptions[event]; if (isFunction(validator)) { - const isValid = validator(...args); + const isValid = validator(...rawArgs); if (!isValid) { warn(`Invalid event arguments: event validation failed for event "${event}".`); } @@ -1257,34 +1257,57 @@ function emit(instance, event, ...args) { } } } + let args = rawArgs; + const isModelListener = event.startsWith('update:'); + // for v-model update:xxx events, apply modifiers on args + const modelArg = isModelListener && event.slice(7); + if (modelArg && modelArg in props) { + const modifiersKey = `${modelArg === 'modelValue' ? 'model' : modelArg}Modifiers`; + const { number, trim } = props[modifiersKey] || EMPTY_OBJ; + if (trim) { + args = rawArgs.map(a => a.trim()); + } + else if (number) { + args = rawArgs.map(toNumber); + } + } if ((process.env.NODE_ENV !== 'production') || false) ; - let handlerName = `on${capitalize(event)}`; + if ((process.env.NODE_ENV !== 'production')) { + const lowerCaseEvent = event.toLowerCase(); + if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) { + warn(`Event "${lowerCaseEvent}" is emitted in component ` + + `${formatComponentName(instance, instance.type)} but the handler is registered for "${event}". ` + + `Note that HTML attributes are case-insensitive and you cannot use ` + + `v-on to listen to camelCase events when using in-DOM templates. ` + + `You should probably use "${hyphenate(event)}" instead of "${event}".`); + } + } + // convert handler name to camelCase. See issue #2249 + let handlerName = toHandlerKey(camelize(event)); let handler = props[handlerName]; // for v-model update:xxx events, also trigger kebab-case equivalent // for props passed via kebab-case - if (!handler && event.startsWith('update:')) { - handlerName = `on${capitalize(hyphenate(event))}`; + if (!handler && isModelListener) { + handlerName = toHandlerKey(hyphenate(event)); handler = props[handlerName]; } - if (!handler) { - handler = props[handlerName + `Once`]; + if (handler) { + callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); + } + const onceHandler = props[handlerName + `Once`]; + if (onceHandler) { if (!instance.emitted) { (instance.emitted = {})[handlerName] = true; } else if (instance.emitted[handlerName]) { return; } - } - if (handler) { - callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); + callWithAsyncErrorHandling(onceHandler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { - const appId = appContext.app ? appContext.app._uid : -1; - const cache = comp.__emits || (comp.__emits = {}); - const cached = cache[appId]; - if (cached !== undefined) { - return cached; + if (!appContext.deopt && comp.__emits !== undefined) { + return comp.__emits; } const raw = comp.emits; let normalized = {}; @@ -1306,7 +1329,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (cache[appId] = null); + return (comp.__emits = null); } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -1314,7 +1337,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { else { extend(normalized, raw); } - return (cache[appId] = normalized); + return (comp.__emits = normalized); } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are @@ -1422,11 +1445,8 @@ function resolvePropValue(options, props, key, value, instance) { return value; } function normalizePropsOptions(comp, appContext, asMixin = false) { - const appId = appContext.app ? appContext.app._uid : -1; - const cache = comp.__props || (comp.__props = {}); - const cached = cache[appId]; - if (cached) { - return cached; + if (!appContext.deopt && comp.__props) { + return comp.__props; } const raw = comp.props; const normalized = {}; @@ -1452,7 +1472,7 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (cache[appId] = EMPTY_ARR); + return (comp.__props = EMPTY_ARR); } if (isArray(raw)) { for (let i = 0; i < raw.length; i++) { @@ -1489,7 +1509,16 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } } - return (cache[appId] = [normalized, needCastKeys]); + return (comp.__props = [normalized, needCastKeys]); +} +function validatePropName(key) { + if (key[0] !== '$') { + return true; + } + else if ((process.env.NODE_ENV !== 'production')) { + warn(`Invalid prop name: "${key}" is a reserved property.`); + } + return false; } // use function string name to check type constructors // so that it works across vms / iframes. @@ -1526,18 +1555,6 @@ function validateProps(props, instance) { validateProp(key, rawValues[key], opt, !hasOwn(rawValues, key)); } } -/** - * dev only - */ -function validatePropName(key) { - if (key[0] !== '$') { - return true; - } - else if ((process.env.NODE_ENV !== 'production')) { - warn(`Invalid prop name: "${key}" is a reserved property.`); - } - return false; -} /** * dev only */ @@ -1685,7 +1702,7 @@ function injectHook(type, hook, target = currentInstance, prepend = false) { return wrappedHook; } else if ((process.env.NODE_ENV !== 'production')) { - const apiName = `on${capitalize(ErrorTypeStrings[type].replace(/ hook$/, ''))}`; + const apiName = toHandlerKey(ErrorTypeStrings[type].replace(/ hook$/, '')); warn(`${apiName} is called when there is no active component instance to be ` + `associated with. ` + `Lifecycle injection APIs can only be used during execution of setup().` + @@ -1841,6 +1858,11 @@ function createAppAPI() { if (__VUE_OPTIONS_API__) { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin); + // global mixin with props/emits de-optimizes props/emits + // normalization caching. + if (mixin.props || mixin.emits) { + context.deopt = true; + } } else if ((process.env.NODE_ENV !== 'production')) { warn('Mixin has already been applied to target app' + @@ -1930,9 +1952,10 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM `a reactive object, or an array of these types.`); }; let getter; - const isRefSource = isRef(source); - if (isRefSource) { + let forceTrigger = false; + if (isRef(source)) { getter = () => source.value; + forceTrigger = !!source._shallow; } else if (isReactive(source)) { getter = () => source; @@ -1994,7 +2017,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM if (cb) { // watch(source, cb) const newValue = runner(); - if (deep || isRefSource || hasChanged(newValue, oldValue)) { + if (deep || forceTrigger || hasChanged(newValue, oldValue)) { // cleanup before running cb again if (cleanup) { cleanup(); @@ -2013,7 +2036,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM runner(); } }; - // important: mark the job as a watcher callback so that scheduler knows it + // important: mark the job as a watcher callback so that scheduler knows // it is allowed to self-trigger (#1727) job.allowRecurse = !!cb; let scheduler; @@ -2086,14 +2109,8 @@ function traverse(value, seen = new Set()) { traverse(value[i], seen); } } - else if (isMap(value)) { - value.forEach((_, key) => { - // to register mutation dep for existing keys - traverse(value.get(key), seen); - }); - } - else if (isSet(value)) { - value.forEach(v => { + else if (isSet(value) || isMap(value)) { + value.forEach((v) => { traverse(v, seen); }); } @@ -2131,8 +2148,13 @@ function inject(key, defaultValue, treatDefaultAsFactory = false) { // a functional component const instance = currentInstance || currentRenderingInstance; if (instance) { - const provides = instance.provides; - if (key in provides) { + // #2400 + // to support `app.use` plugins, + // fallback to appContext's `provides` if the intance is at root + const provides = instance.parent == null + ? instance.vnode.appContext && instance.vnode.appContext.provides + : instance.parent.provides; + if (provides && key in provides) { // TS doesn't allow symbol as index type return provides[key]; } @@ -2162,7 +2184,7 @@ function createDuplicateChecker() { }; } let isInBeforeCreate = false; -function applyOptions(instance, options, deferredData = [], deferredWatch = [], asMixin = false) { +function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) { const { // composition mixins, extends: extendsOptions, @@ -2181,18 +2203,18 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], // applyOptions is called non-as-mixin once per instance if (!asMixin) { isInBeforeCreate = true; - callSyncHook('beforeCreate', options, publicThis, globalMixins); + callSyncHook('beforeCreate', "bc" /* BEFORE_CREATE */, options, instance, globalMixins); isInBeforeCreate = false; // global mixins are applied first - applyMixins(instance, globalMixins, deferredData, deferredWatch); + applyMixins(instance, globalMixins, deferredData, deferredWatch, deferredProvide); } // extending a base component... if (extendsOptions) { - applyOptions(instance, extendsOptions, deferredData, deferredWatch, true); + applyOptions(instance, extendsOptions, deferredData, deferredWatch, deferredProvide, true); } // local mixins if (mixins) { - applyMixins(instance, mixins, deferredData, deferredWatch); + applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide); } const checkDuplicateProperties = (process.env.NODE_ENV !== 'production') ? createDuplicateChecker() : null; if ((process.env.NODE_ENV !== 'production')) { @@ -2321,12 +2343,19 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], }); } // fixed by xxxxxx - if (!__VUE_CREATED_DEFERRED__ && provideOptions) { - const provides = isFunction(provideOptions) - ? provideOptions.call(publicThis) - : provideOptions; - for (const key in provides) { - provide(key, provides[key]); + if (!__VUE_CREATED_DEFERRED__) { + if (provideOptions) { + deferredProvide.push(provideOptions); + } + if (!asMixin && deferredProvide.length) { + deferredProvide.forEach(provideOptions => { + const provides = isFunction(provideOptions) + ? provideOptions.call(publicThis) + : provideOptions; + for (const key in provides) { + provide(key, provides[key]); + } + }); } } // asset options. @@ -2346,11 +2375,11 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], // lifecycle options if (__VUE_CREATED_DEFERRED__) { ctx.$callSyncHook = function (name) { - return callSyncHook(name, options, publicThis, globalMixins); + return callSyncHook(name, "c" /* CREATED */, options, instance, globalMixins); }; } else if (!asMixin) { - callSyncHook('created', options, publicThis, globalMixins); + callSyncHook('created', "c" /* CREATED */, options, instance, globalMixins); } if (beforeMount) { onBeforeMount(beforeMount.bind(publicThis)); @@ -2396,44 +2425,44 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], instance.ctx.$onApplyOptions(options, instance, publicThis); } } -function callSyncHook(name, options, ctx, globalMixins) { - callHookFromMixins(name, globalMixins, ctx); +function callSyncHook(name, type, options, instance, globalMixins) { + callHookFromMixins(name, type, globalMixins, instance); const { extends: base, mixins } = options; if (base) { - callHookFromExtends(name, base, ctx); + callHookFromExtends(name, type, base, instance); } if (mixins) { - callHookFromMixins(name, mixins, ctx); + callHookFromMixins(name, type, mixins, instance); } const selfHook = options[name]; if (selfHook) { - selfHook.call(ctx); + callWithAsyncErrorHandling(selfHook.bind(instance.proxy), instance, type); } } -function callHookFromExtends(name, base, ctx) { +function callHookFromExtends(name, type, base, instance) { if (base.extends) { - callHookFromExtends(name, base.extends, ctx); + callHookFromExtends(name, type, base.extends, instance); } const baseHook = base[name]; if (baseHook) { - baseHook.call(ctx); + callWithAsyncErrorHandling(baseHook.bind(instance.proxy), instance, type); } } -function callHookFromMixins(name, mixins, ctx) { +function callHookFromMixins(name, type, mixins, instance) { for (let i = 0; i < mixins.length; i++) { const chainedMixins = mixins[i].mixins; if (chainedMixins) { - callHookFromMixins(name, chainedMixins, ctx); + callHookFromMixins(name, type, chainedMixins, instance); } const fn = mixins[i][name]; if (fn) { - fn.call(ctx); + callWithAsyncErrorHandling(fn.bind(instance.proxy), instance, type); } } } -function applyMixins(instance, mixins, deferredData, deferredWatch) { +function applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide) { for (let i = 0; i < mixins.length; i++) { - applyOptions(instance, mixins[i], deferredData, deferredWatch, true); + applyOptions(instance, mixins[i], deferredData, deferredWatch, deferredProvide, true); } } function resolveData(instance, dataFn, publicThis) { @@ -2546,7 +2575,7 @@ const publicPropertiesMap = extend(Object.create(null), { $emit: i => i.emit, $options: i => (__VUE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type), $forceUpdate: i => () => queueJob(i.update), - // $nextTick: () => nextTick, // fixed by xxxxxx + // $nextTick: i => nextTick.bind(i.proxy!), // fixed by xxxxxx $watch: i => (__VUE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP) }); const PublicInstanceProxyHandlers = { @@ -2556,6 +2585,10 @@ const PublicInstanceProxyHandlers = { if (key === "__v_skip" /* SKIP */) { return true; } + // for internal formatters to know that this is a Vue instance + if ((process.env.NODE_ENV !== 'production') && key === '__isVue') { + return true; + } // data / props / ctx // This getter gets called for every property access on the render context // during render and is a major hotspot. The most expensive part of this @@ -2900,7 +2933,7 @@ function setupStatefulComponent(instance, isSSR) { } } // 0. create render proxy property access cache - instance.accessCache = {}; + instance.accessCache = Object.create(null); // 1. create public instance / render proxy // also mark it raw so it's never observed instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers); @@ -3077,7 +3110,7 @@ function computed$1(getterOrOptions) { } // Core API ------------------------------------------------------------------ -const version = "3.0.0"; +const version = "3.0.2"; // import deepCopy from './deepCopy' /** diff --git a/packages/uni-mp-weixin/dist/uni.api.esm.js b/packages/uni-mp-weixin/dist/uni.api.esm.js index ea7871836..7ef01a08b 100644 --- a/packages/uni-mp-weixin/dist/uni.api.esm.js +++ b/packages/uni-mp-weixin/dist/uni.api.esm.js @@ -487,19 +487,7 @@ const getSystemInfo = { returnValue: addSafeAreaInsets }; const getSystemInfoSync = getSystemInfo; -const redirectTo = {}; -const createCanvasContext = { - returnValue(fromRes, toRes) { - const measureText = fromRes.measureText; - toRes.measureText = function (text, callback) { - const textMetrics = measureText.call(this, text); - if (typeof callback === 'function') { - setTimeout(() => callback(textMetrics), 0); - } - return textMetrics; - }; - } -}; +const redirectTo = {}; const getProvider = initGetProvider({ oauth: ['weixin'], @@ -518,8 +506,7 @@ var protocols = /*#__PURE__*/Object.freeze({ redirectTo: redirectTo, previewImage: previewImage, getSystemInfo: getSystemInfo, - getSystemInfoSync: getSystemInfoSync, - createCanvasContext: createCanvasContext + getSystemInfoSync: getSystemInfoSync }); var index = initUni(shims, protocols); diff --git a/packages/uni-quickapp-webview/dist/uni.api.esm.js b/packages/uni-quickapp-webview/dist/uni.api.esm.js index 09c73991a..5c520ea24 100644 --- a/packages/uni-quickapp-webview/dist/uni.api.esm.js +++ b/packages/uni-quickapp-webview/dist/uni.api.esm.js @@ -487,19 +487,7 @@ const getSystemInfo = { returnValue: addSafeAreaInsets }; const getSystemInfoSync = getSystemInfo; -const redirectTo = {}; -const createCanvasContext = { - returnValue(fromRes, toRes) { - const measureText = fromRes.measureText; - toRes.measureText = function (text, callback) { - const textMetrics = measureText.call(this, text); - if (typeof callback === 'function') { - setTimeout(() => callback(textMetrics), 0); - } - return textMetrics; - }; - } -}; +const redirectTo = {}; const providers = { oauth: [], @@ -525,8 +513,7 @@ var protocols = /*#__PURE__*/Object.freeze({ redirectTo: redirectTo, previewImage: previewImage, getSystemInfo: getSystemInfo, - getSystemInfoSync: getSystemInfoSync, - createCanvasContext: createCanvasContext + getSystemInfoSync: getSystemInfoSync }); var index = initUni(shims, protocols); -- GitLab