@vue/runtime-core
Version:
@vue/runtime-core
1,382 lines (1,367 loc) • 169 kB
JavaScript
import { pauseTracking, resumeTracking, isRef, toRaw, isReactive, unlock, lock, effect, stop, reactive, shallowReadonly, computed as computed$1 } from '@vue/reactivity';
export { effect, isReactive, isReadonly, isRef, markNonReactive, markReadonly, reactive, readonly, ref, toRaw, toRefs } from '@vue/reactivity';
// Make a map and return a function for checking if a key
// is in that map.
//
// IMPORTANT: all calls of this function must be prefixed with /*#__PURE__*/
// So that rollup can tree-shake them if necessary.
function makeMap(str, expectsLowerCase) {
const map = Object.create(null);
const list = str.split(',');
for (let i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val];
}
// Patch flags are optimization hints generated by the compiler.
// when a block with dynamicChildren is encountered during diff, the algorithm
// enters "optimized mode". In this mode, we know that the vdom is produced by
// a render function generated by the compiler, so the algorithm only needs to
// handle updates explicitly marked by these patch flags.
// runtime object for public consumption
const PublicPatchFlags = {
TEXT: 1 /* TEXT */,
CLASS: 2 /* CLASS */,
STYLE: 4 /* STYLE */,
PROPS: 8 /* PROPS */,
NEED_PATCH: 32 /* NEED_PATCH */,
FULL_PROPS: 16 /* FULL_PROPS */,
KEYED_FRAGMENT: 128 /* KEYED_FRAGMENT */,
UNKEYED_FRAGMENT: 256 /* UNKEYED_FRAGMENT */,
DYNAMIC_SLOTS: 512 /* DYNAMIC_SLOTS */,
BAIL: -1 /* BAIL */
};
const EMPTY_OBJ = (process.env.NODE_ENV !== 'production')
? Object.freeze({})
: {};
const EMPTY_ARR = [];
const NOOP = () => { };
/**
* Always return false.
*/
const NO = () => false;
const extend = (a, b) => {
for (const key in b) {
a[key] = b[key];
}
return a;
};
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (val, key) => hasOwnProperty.call(val, key);
const isArray = Array.isArray;
const isFunction = (val) => typeof val === 'function';
const isString = (val) => typeof val === 'string';
const isObject = (val) => val !== null && typeof val === 'object';
function isPromise(val) {
return isObject(val) && isFunction(val.then) && isFunction(val.catch);
}
const objectToString = Object.prototype.toString;
const toTypeString = (value) => objectToString.call(value);
function toRawType(value) {
return toTypeString(value).slice(8, -1);
}
const isPlainObject = (val) => toTypeString(val) === '[object Object]';
const isReservedProp = /*#__PURE__*/ makeMap('key,ref,' +
'onVnodeBeforeMount,onVnodeMounted,' +
'onVnodeBeforeUpdate,onVnodeUpdated,' +
'onVnodeBeforeUnmount,onVnodeUnmounted');
function cacheStringFunction(fn) {
const cache = Object.create(null);
return ((str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
});
}
const camelizeRE = /-(\w)/g;
const camelize = cacheStringFunction((str) => {
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
});
const hyphenateRE = /\B([A-Z])/g;
const hyphenate = cacheStringFunction((str) => {
return str.replace(hyphenateRE, '-$1').toLowerCase();
});
const capitalize = cacheStringFunction((str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
});
// compare whether a value has changed, accounting for NaN.
const hasChanged = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue);
const ErrorTypeStrings = {
["bc" /* BEFORE_CREATE */]: 'beforeCreate hook',
["c" /* CREATED */]: 'created hook',
["bm" /* BEFORE_MOUNT */]: 'beforeMount hook',
["m" /* MOUNTED */]: 'mounted hook',
["bu" /* BEFORE_UPDATE */]: 'beforeUpdate hook',
["u" /* UPDATED */]: 'updated',
["bum" /* BEFORE_UNMOUNT */]: 'beforeUnmount hook',
["um" /* UNMOUNTED */]: 'unmounted hook',
["a" /* ACTIVATED */]: 'activated hook',
["da" /* DEACTIVATED */]: 'deactivated hook',
["ec" /* ERROR_CAPTURED */]: 'errorCaptured hook',
["rtc" /* RENDER_TRACKED */]: 'renderTracked hook',
["rtg" /* RENDER_TRIGGERED */]: 'renderTriggered hook',
[0 /* SETUP_FUNCTION */]: 'setup function',
[1 /* RENDER_FUNCTION */]: 'render function',
[2 /* WATCH_GETTER */]: 'watcher getter',
[3 /* WATCH_CALLBACK */]: 'watcher callback',
[4 /* WATCH_CLEANUP */]: 'watcher cleanup function',
[5 /* NATIVE_EVENT_HANDLER */]: 'native event handler',
[6 /* COMPONENT_EVENT_HANDLER */]: 'component event handler',
[7 /* DIRECTIVE_HOOK */]: 'directive hook',
[8 /* TRANSITION_HOOK */]: 'transition hook',
[9 /* APP_ERROR_HANDLER */]: 'app errorHandler',
[10 /* APP_WARN_HANDLER */]: 'app warnHandler',
[11 /* FUNCTION_REF */]: 'ref function',
[12 /* SCHEDULER */]: 'scheduler flush. This is likely a Vue internals bug. ' +
'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue'
};
function callWithErrorHandling(fn, instance, type, args) {
let res;
try {
res = args ? fn(...args) : fn();
}
catch (err) {
handleError(err, instance, type);
}
return res;
}
function callWithAsyncErrorHandling(fn, instance, type, args) {
if (isFunction(fn)) {
const res = callWithErrorHandling(fn, instance, type, args);
if (res != null && !res._isVue && isPromise(res)) {
res.catch((err) => {
handleError(err, instance, type);
});
}
return res;
}
for (let i = 0; i < fn.length; i++) {
callWithAsyncErrorHandling(fn[i], instance, type, args);
}
}
function handleError(err, instance, type) {
const contextVNode = instance ? instance.vnode : null;
if (instance) {
let cur = instance.parent;
// the exposed instance is the render proxy to keep it consistent with 2.x
const exposedInstance = instance.proxy;
// in production the hook receives only the error code
const errorInfo = (process.env.NODE_ENV !== 'production') ? ErrorTypeStrings[type] : type;
while (cur) {
const errorCapturedHooks = cur.ec;
if (errorCapturedHooks !== null) {
for (let i = 0; i < errorCapturedHooks.length; i++) {
if (errorCapturedHooks[i](err, exposedInstance, errorInfo)) {
return;
}
}
}
cur = cur.parent;
}
// app-level handling
const appErrorHandler = instance.appContext.config.errorHandler;
if (appErrorHandler) {
callWithErrorHandling(appErrorHandler, null, 9 /* APP_ERROR_HANDLER */, [err, exposedInstance, errorInfo]);
return;
}
}
logError(err, type, contextVNode);
}
// Test-only toggle for testing the unhandled warning behavior
let forceRecover = false;
function logError(err, type, contextVNode) {
// default behavior is crash in prod & test, recover in dev.
if ((process.env.NODE_ENV !== 'production') && (forceRecover || !(process.env.NODE_ENV === 'test'))) {
const info = ErrorTypeStrings[type];
if (contextVNode) {
pushWarningContext(contextVNode);
}
warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`);
console.error(err);
if (contextVNode) {
popWarningContext();
}
}
else {
throw err;
}
}
const stack = [];
function pushWarningContext(vnode) {
stack.push(vnode);
}
function popWarningContext() {
stack.pop();
}
function warn(msg, ...args) {
// avoid props formatting or warn handler tracking deps that might be mutated
// during patch, leading to infinite recursion.
pauseTracking();
const instance = stack.length ? stack[stack.length - 1].component : null;
const appWarnHandler = instance && instance.appContext.config.warnHandler;
const trace = getComponentTrace();
if (appWarnHandler) {
callWithErrorHandling(appWarnHandler, instance, 10 /* APP_WARN_HANDLER */, [
msg + args.join(''),
instance && instance.proxy,
trace
.map(({ vnode }) => `at <${formatComponentName(vnode)}>`)
.join('\n'),
trace
]);
}
else {
const warnArgs = [`[Vue warn]: ${msg}`, ...args];
if (trace.length &&
// avoid spamming console during tests
!(process.env.NODE_ENV === 'test')) {
warnArgs.push(`\n`, ...formatTrace(trace));
}
console.warn(...warnArgs);
}
resumeTracking();
}
function getComponentTrace() {
let currentVNode = stack[stack.length - 1];
if (!currentVNode) {
return [];
}
// we can't just use the stack because it will be incomplete during updates
// that did not start from the root. Re-construct the parent chain using
// instance parent pointers.
const normalizedStack = [];
while (currentVNode) {
const last = normalizedStack[0];
if (last && last.vnode === currentVNode) {
last.recurseCount++;
}
else {
normalizedStack.push({
vnode: currentVNode,
recurseCount: 0
});
}
const parentInstance = currentVNode.component
.parent;
currentVNode = parentInstance && parentInstance.vnode;
}
return normalizedStack;
}
function formatTrace(trace) {
const logs = [];
trace.forEach((entry, i) => {
logs.push(...(i === 0 ? [] : [`\n`]), ...formatTraceEntry(entry));
});
return logs;
}
function formatTraceEntry({ vnode, recurseCount }) {
const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``;
const open = ` at <${formatComponentName(vnode)}`;
const close = `>` + postfix;
const rootLabel = vnode.component.parent == null ? `(Root)` : ``;
return vnode.props
? [open, ...formatProps(vnode.props), close, rootLabel]
: [open + close, rootLabel];
}
const classifyRE = /(?:^|[-_])(\w)/g;
const classify = (str) => str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '');
function formatComponentName(vnode, file) {
const Component = vnode.type;
let name = isFunction(Component)
? Component.displayName || Component.name
: Component.name;
if (!name && file) {
const match = file.match(/([^/\\]+)\.vue$/);
if (match) {
name = match[1];
}
}
return name ? classify(name) : 'Anonymous';
}
function formatProps(props) {
const res = [];
const keys = Object.keys(props);
keys.slice(0, 3).forEach(key => {
res.push(...formatProp(key, props[key]));
});
if (keys.length > 3) {
res.push(` ...`);
}
return res;
}
function formatProp(key, value, raw) {
if (isString(value)) {
value = JSON.stringify(value);
return raw ? value : [`${key}=${value}`];
}
else if (typeof value === 'number' ||
typeof value === 'boolean' ||
value == null) {
return raw ? value : [`${key}=${value}`];
}
else if (isRef(value)) {
value = formatProp(key, toRaw(value.value), true);
return raw ? value : [`${key}=Ref<`, value, `>`];
}
else if (isFunction(value)) {
return [`${key}=fn${value.name ? `<${value.name}>` : ``}`];
}
else {
value = toRaw(value);
return raw ? value : [`${key}=`, value];
}
}
// SFC scoped style ID management.
// These are only used in esm-bundler builds, but since exports cannot be
// conditional, we can only drop inner implementations in non-bundler builds.
let currentScopeId = null;
const scopeIdStack = [];
function pushScopeId(id) {
{
scopeIdStack.push((currentScopeId = id));
}
}
function popScopeId() {
{
scopeIdStack.pop();
currentScopeId = scopeIdStack[scopeIdStack.length - 1] || null;
}
}
function withScopeId(id) {
{
return ((fn) => {
return function () {
pushScopeId(id);
const res = fn.apply(this, arguments);
popScopeId();
return res;
};
});
}
}
const Fragment = Symbol((process.env.NODE_ENV !== 'production') ? 'Fragment' : undefined);
const Portal = Symbol((process.env.NODE_ENV !== 'production') ? 'Portal' : undefined);
const Text = Symbol((process.env.NODE_ENV !== 'production') ? 'Text' : undefined);
const Comment = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : 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:
//
// function render() {
// return (openBlock(),createBlock('div', null, [...]))
// }
//
// disableTracking is true when creating a fragment block, since a fragment
// always diffs its children.
function openBlock(disableTracking) {
blockStack.push((currentBlock = disableTracking ? 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;
// 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:
// _cache[1] || (
// setBlockTracking(-1),
// _cache[1] = createVNode(...),
// setBlockTracking(1),
// _cache[1]
// )
function setBlockTracking(value) {
shouldTrack += 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.
function createBlock(type, props, children, patchFlag, dynamicProps) {
// avoid a block with patchFlag tracking itself
shouldTrack--;
const vnode = createVNode(type, props, children, patchFlag, dynamicProps);
shouldTrack++;
// save current block children on the block vnode
vnode.dynamicChildren = currentBlock || EMPTY_ARR;
// close block
blockStack.pop();
currentBlock = blockStack[blockStack.length - 1] || null;
// a block is always going to be patched, so track it as a child of its
// parent block
if (currentBlock !== null) {
currentBlock.push(vnode);
}
return vnode;
}
function isVNode(value) {
return value ? value._isVNode === true : false;
}
function isSameVNodeType(n1, n2) {
if (
(process.env.NODE_ENV !== 'production') &&
n2.shapeFlag & 6 /* COMPONENT */ &&
n2.type.__hmrUpdated) {
// HMR only: if the component has been hot-updated, force a reload.
return false;
}
return n1.type === n2.type && n1.key === n2.key;
}
function createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null) {
if ((process.env.NODE_ENV !== 'production') && !type) {
warn(`Invalid vnode type when creating vnode: ${type}.`);
type = Comment;
}
// class & style normalization.
if (props !== null) {
// for reactive or proxy objects, we need to clone it to enable mutation.
if (isReactive(props) || SetupProxySymbol in props) {
props = extend({}, props);
}
let { class: klass, style } = props;
if (klass != null && !isString(klass)) {
props.class = normalizeClass(klass);
}
if (style != null) {
// reactive state objects need to be cloned since they are likely to be
// mutated
if (isReactive(style) && !isArray(style)) {
style = extend({}, style);
}
props.style = normalizeStyle(style);
}
}
// encode the vnode type information into a bitmap
const shapeFlag = isString(type)
? 1 /* ELEMENT */
: type.__isSuspense === true
? 64 /* SUSPENSE */
: isObject(type)
? 4 /* STATEFUL_COMPONENT */
: isFunction(type)
? 2 /* FUNCTIONAL_COMPONENT */
: 0;
const vnode = {
_isVNode: true,
type,
props,
key: (props !== null && props.key) || null,
ref: (props !== null && props.ref) || null,
scopeId: currentScopeId,
children: null,
component: null,
suspense: null,
dirs: null,
transition: null,
el: null,
anchor: null,
target: null,
shapeFlag,
patchFlag,
dynamicProps,
dynamicChildren: null,
appContext: null
};
normalizeChildren(vnode, children);
// 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.
if (shouldTrack > 0 &&
currentBlock !== null &&
(patchFlag > 0 ||
shapeFlag & 4 /* STATEFUL_COMPONENT */ ||
shapeFlag & 2 /* FUNCTIONAL_COMPONENT */)) {
currentBlock.push(vnode);
}
return vnode;
}
function cloneVNode(vnode, extraProps) {
// This is intentionally NOT using spread or extend to avoid the runtime
// key enumeration cost.
return {
_isVNode: true,
type: vnode.type,
props: extraProps
? vnode.props
? mergeProps(vnode.props, extraProps)
: extraProps
: vnode.props,
key: vnode.key,
ref: vnode.ref,
scopeId: vnode.scopeId,
children: vnode.children,
target: vnode.target,
shapeFlag: vnode.shapeFlag,
patchFlag: vnode.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,
el: vnode.el,
anchor: vnode.anchor
};
}
function createTextVNode(text = ' ', flag = 0) {
return createVNode(Text, null, text, flag);
}
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
? createBlock(Comment, null, text)
: createVNode(Comment, null, text);
}
function normalizeVNode(child) {
if (child == null) {
// 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 {
// primitive types
return createVNode(Text, null, String(child));
}
}
// optimized normalization for template-compiled render fns
function cloneIfMounted(child) {
return child.el === null ? child : cloneVNode(child);
}
function normalizeChildren(vnode, children) {
let type = 0;
if (children == null) {
children = null;
}
else if (isArray(children)) {
type = 16 /* ARRAY_CHILDREN */;
}
else if (typeof children === 'object') {
type = 32 /* SLOTS_CHILDREN */;
}
else if (isFunction(children)) {
children = { default: children };
type = 32 /* SLOTS_CHILDREN */;
}
else {
children = String(children);
type = 8 /* TEXT_CHILDREN */;
}
vnode.children = children;
vnode.shapeFlag |= type;
}
function normalizeStyle(value) {
if (isArray(value)) {
const res = {};
for (let i = 0; i < value.length; i++) {
const normalized = normalizeStyle(value[i]);
if (normalized) {
for (const key in normalized) {
res[key] = normalized[key];
}
}
}
return res;
}
else if (isObject(value)) {
return value;
}
}
function normalizeClass(value) {
let res = '';
if (isString(value)) {
res = value;
}
else if (isArray(value)) {
for (let i = 0; i < value.length; i++) {
res += normalizeClass(value[i]) + ' ';
}
}
else if (isObject(value)) {
for (const name in value) {
if (value[name]) {
res += name + ' ';
}
}
}
return res.trim();
}
const handlersRE = /^on|^vnode/;
function mergeProps(...args) {
const ret = {};
extend(ret, args[0]);
for (let i = 1; i < args.length; i++) {
const toMerge = args[i];
for (const key in toMerge) {
if (key === 'class') {
ret.class = normalizeClass([ret.class, toMerge.class]);
}
else if (key === 'style') {
ret.style = normalizeStyle([ret.style, toMerge.style]);
}
else if (handlersRE.test(key)) {
// on*, vnode*
const existing = ret[key];
ret[key] = existing
? [].concat(existing, toMerge[key])
: toMerge[key];
}
else {
ret[key] = toMerge[key];
}
}
}
return ret;
}
const queue = [];
const postFlushCbs = [];
const p = Promise.resolve();
let isFlushing = false;
let isFlushPending = false;
const RECURSION_LIMIT = 100;
function nextTick(fn) {
return fn ? p.then(fn) : p;
}
function queueJob(job) {
if (!queue.includes(job)) {
queue.push(job);
queueFlush();
}
}
function queuePostFlushCb(cb) {
if (!isArray(cb)) {
postFlushCbs.push(cb);
}
else {
postFlushCbs.push(...cb);
}
queueFlush();
}
function queueFlush() {
if (!isFlushing && !isFlushPending) {
isFlushPending = true;
nextTick(flushJobs);
}
}
const dedupe = (cbs) => [...new Set(cbs)];
function flushPostFlushCbs(seen) {
if (postFlushCbs.length) {
const cbs = dedupe(postFlushCbs);
postFlushCbs.length = 0;
if ((process.env.NODE_ENV !== 'production')) {
seen = seen || new Map();
}
for (let i = 0; i < cbs.length; i++) {
if ((process.env.NODE_ENV !== 'production')) {
checkRecursiveUpdates(seen, cbs[i]);
}
cbs[i]();
}
}
}
function flushJobs(seen) {
isFlushPending = false;
isFlushing = true;
let job;
if ((process.env.NODE_ENV !== 'production')) {
seen = seen || new Map();
}
while ((job = queue.shift())) {
if ((process.env.NODE_ENV !== 'production')) {
checkRecursiveUpdates(seen, job);
}
callWithErrorHandling(job, null, 12 /* SCHEDULER */);
}
flushPostFlushCbs(seen);
isFlushing = false;
// some postFlushCb queued jobs!
// keep flushing until it drains.
if (queue.length || postFlushCbs.length) {
flushJobs(seen);
}
}
function checkRecursiveUpdates(seen, fn) {
if (!seen.has(fn)) {
seen.set(fn, 1);
}
else {
const count = seen.get(fn);
if (count > RECURSION_LIMIT) {
throw new Error('Maximum recursive updates exceeded. ' +
"You may have code that is mutating state in your component's " +
'render function or updated hook or watcher source function.');
}
else {
seen.set(fn, count + 1);
}
}
}
// mark the current rendering instance for asset resolution (e.g.
// resolveComponent, resolveDirective) during render
let currentRenderingInstance = null;
// dev only flag to track whether $attrs was used during render.
// If $attrs was used during render then the warning for failed attrs
// fallthrough can be suppressed.
let accessedAttrs = false;
function markAttrsAccessed() {
accessedAttrs = true;
}
function renderComponentRoot(instance) {
const { type: Component, vnode, proxy, withProxy, props, slots, attrs, emit } = instance;
let result;
currentRenderingInstance = instance;
if ((process.env.NODE_ENV !== 'production')) {
accessedAttrs = false;
}
try {
if (vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */) {
result = normalizeVNode(instance.render.call(withProxy || proxy));
}
else {
// functional
const render = Component;
result = normalizeVNode(render.length > 1
? render(props, {
attrs,
slots,
emit
})
: render(props, null /* we know it doesn't need it */));
}
// attr merging
if (Component.props != null &&
Component.inheritAttrs !== false &&
attrs !== EMPTY_OBJ &&
Object.keys(attrs).length) {
if (result.shapeFlag & 1 /* ELEMENT */ ||
result.shapeFlag & 6 /* COMPONENT */) {
result = cloneVNode(result, attrs);
}
else if ((process.env.NODE_ENV !== 'production') && !accessedAttrs && result.type !== Comment) {
warn(`Extraneous non-props attributes (${Object.keys(attrs).join(',')}) ` +
`were passed to component but could not be automatically inherited ` +
`because component renders fragment or text root nodes.`);
}
}
// inherit transition data
if (vnode.transition != null) {
if ((process.env.NODE_ENV !== 'production') &&
!(result.shapeFlag & 6 /* COMPONENT */) &&
!(result.shapeFlag & 1 /* ELEMENT */) &&
result.type !== Comment) {
warn(`Component inside <Transition> renders non-element root node ` +
`that cannot be animated.`);
}
result.transition = vnode.transition;
}
}
catch (err) {
handleError(err, instance, 1 /* RENDER_FUNCTION */);
result = createVNode(Comment);
}
currentRenderingInstance = null;
return result;
}
function shouldUpdateComponent(prevVNode, nextVNode, parentComponent, optimized) {
const { props: prevProps, children: prevChildren } = prevVNode;
const { props: nextProps, children: nextChildren, patchFlag } = nextVNode;
// Parent component's render function was hot-updated. Since this may have
// caused the child component's slots content to have changed, we need to
// force the child to update as well.
if (
(process.env.NODE_ENV !== 'production') &&
(prevChildren || nextChildren) &&
parentComponent &&
parentComponent.renderUpdated) {
return true;
}
if (patchFlag > 0) {
if (patchFlag & 512 /* DYNAMIC_SLOTS */) {
// slot content that references values that might have changed,
// e.g. in a v-for
return true;
}
if (patchFlag & 16 /* FULL_PROPS */) {
// presence of this flag indicates props are always non-null
return hasPropsChanged(prevProps, nextProps);
}
else if (patchFlag & 8 /* PROPS */) {
const dynamicProps = nextVNode.dynamicProps;
for (let i = 0; i < dynamicProps.length; i++) {
const key = dynamicProps[i];
if (nextProps[key] !== prevProps[key]) {
return true;
}
}
}
}
else if (!optimized) {
// this path is only taken by manually written render functions
// so presence of any children leads to a forced update
if (prevChildren != null || nextChildren != null) {
if (nextChildren == null || !nextChildren.$stable) {
return true;
}
}
if (prevProps === nextProps) {
return false;
}
if (prevProps === null) {
return nextProps !== null;
}
if (nextProps === null) {
return true;
}
return hasPropsChanged(prevProps, nextProps);
}
return false;
}
function hasPropsChanged(prevProps, nextProps) {
const nextKeys = Object.keys(nextProps);
if (nextKeys.length !== Object.keys(prevProps).length) {
return true;
}
for (let i = 0; i < nextKeys.length; i++) {
const key = nextKeys[i];
if (nextProps[key] !== prevProps[key]) {
return true;
}
}
return false;
}
function updateHOCHostEl({ vnode, parent }, el // HostNode
) {
while (parent && parent.subTree === vnode) {
(vnode = parent.vnode).el = el;
parent = parent.parent;
}
}
// resolve raw VNode data.
// - filter out reserved keys (key, ref, slots)
// - extract class and style into $attrs (to be merged onto child
// component root)
// - for the rest:
// - if has declared props: put declared ones in `props`, the rest in `attrs`
// - else: everything goes in `props`.
function resolveProps(instance, rawProps, _options) {
const hasDeclaredProps = _options != null;
if (!rawProps && !hasDeclaredProps) {
return;
}
const { 0: options, 1: needCastKeys } = normalizePropsOptions(_options);
const props = {};
let attrs = void 0;
// update the instance propsProxy (passed to setup()) to trigger potential
// changes
const propsProxy = instance.propsProxy;
const setProp = propsProxy
? (key, val) => {
props[key] = val;
propsProxy[key] = val;
}
: (key, val) => {
props[key] = val;
};
// allow mutation of propsProxy (which is readonly by default)
unlock();
if (rawProps != null) {
for (const key in rawProps) {
// key, ref are reserved and never passed down
if (key === 'key' || key === 'ref')
continue;
// prop option names are camelized during normalization, so to support
// kebab -> camel conversion here we need to camelize the key.
const camelKey = camelize(key);
if (hasDeclaredProps && !hasOwn(options, camelKey)) {
(attrs || (attrs = {}))[key] = rawProps[key];
}
else {
setProp(camelKey, rawProps[key]);
}
}
}
if (hasDeclaredProps) {
// set default values & cast booleans
for (let i = 0; i < needCastKeys.length; i++) {
const key = needCastKeys[i];
let opt = options[key];
if (opt == null)
continue;
const isAbsent = !hasOwn(props, key);
const hasDefault = hasOwn(opt, 'default');
const currentValue = props[key];
// default values
if (hasDefault && currentValue === undefined) {
const defaultValue = opt.default;
setProp(key, isFunction(defaultValue) ? defaultValue() : defaultValue);
}
// boolean casting
if (opt[0 /* shouldCast */]) {
if (isAbsent && !hasDefault) {
setProp(key, false);
}
else if (opt[1 /* shouldCastTrue */] &&
(currentValue === '' || currentValue === hyphenate(key))) {
setProp(key, true);
}
}
}
// validation
if ((process.env.NODE_ENV !== 'production') && rawProps) {
for (const key in options) {
let opt = options[key];
if (opt == null)
continue;
let rawValue;
if (!(key in rawProps) && hyphenate(key) in rawProps) {
rawValue = rawProps[hyphenate(key)];
}
else {
rawValue = rawProps[key];
}
validateProp(key, toRaw(rawValue), opt, !hasOwn(props, key));
}
}
}
else {
// if component has no declared props, $attrs === $props
attrs = props;
}
// in case of dynamic props, check if we need to delete keys from
// the props proxy
const { patchFlag } = instance.vnode;
if (propsProxy !== null &&
(patchFlag === 0 || patchFlag & 16 /* FULL_PROPS */)) {
const rawInitialProps = toRaw(propsProxy);
for (const key in rawInitialProps) {
if (!hasOwn(props, key)) {
delete propsProxy[key];
}
}
}
// lock readonly
lock();
instance.props = props;
instance.attrs = options ? attrs || EMPTY_OBJ : props;
}
const normalizationMap = new WeakMap();
function normalizePropsOptions(raw) {
if (!raw) {
return [];
}
if (normalizationMap.has(raw)) {
return normalizationMap.get(raw);
}
const options = {};
const needCastKeys = [];
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 (normalizedKey[0] !== '$') {
options[normalizedKey] = EMPTY_OBJ;
}
else if ((process.env.NODE_ENV !== 'production')) {
warn(`Invalid prop name: "${normalizedKey}" is a reserved property.`);
}
}
}
else {
if ((process.env.NODE_ENV !== 'production') && !isObject(raw)) {
warn(`invalid props options`, raw);
}
for (const key in raw) {
const normalizedKey = camelize(key);
if (normalizedKey[0] !== '$') {
const opt = raw[key];
const prop = (options[normalizedKey] =
isArray(opt) || isFunction(opt) ? { type: opt } : opt);
if (prop != null) {
const booleanIndex = getTypeIndex(Boolean, prop.type);
const stringIndex = getTypeIndex(String, prop.type);
prop[0 /* shouldCast */] = booleanIndex > -1;
prop[1 /* shouldCastTrue */] = booleanIndex < stringIndex;
// if the prop needs boolean casting or default value
if (booleanIndex > -1 || hasOwn(prop, 'default')) {
needCastKeys.push(normalizedKey);
}
}
}
else if ((process.env.NODE_ENV !== 'production')) {
warn(`Invalid prop name: "${normalizedKey}" is a reserved property.`);
}
}
}
const normalized = [options, needCastKeys];
normalizationMap.set(raw, normalized);
return normalized;
}
// 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 (isObject(expectedTypes)) {
return isSameType(expectedTypes, type) ? 0 : -1;
}
return -1;
}
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;
}
}
// custom validator
if (validator && !validator(value)) {
warn('Invalid prop: custom validator check failed for prop "' + name + '".');
}
}
const isSimpleType = /*#__PURE__*/ makeMap('String,Number,Boolean,Function,Symbol');
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 (expectedType === 'Object') {
valid = toRawType(value) === 'Object';
}
else if (expectedType === 'Array') {
valid = isArray(value);
}
else {
valid = value instanceof type;
}
return {
valid,
expectedType
};
}
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;
}
function styleValue(value, type) {
if (type === 'String') {
return `"${value}"`;
}
else if (type === 'Number') {
return `${Number(value)}`;
}
else {
return `${value}`;
}
}
function isExplicable(type) {
const explicitTypes = ['string', 'number', 'boolean'];
return explicitTypes.some(elem => type.toLowerCase() === elem);
}
function isBoolean(...args) {
return args.some(elem => elem.toLowerCase() === 'boolean');
}
const normalizeSlotValue = (value) => isArray(value)
? value.map(normalizeVNode)
: [normalizeVNode(value)];
const normalizeSlot = (key, rawSlot) => (props) => {
if ((process.env.NODE_ENV !== 'production') && currentInstance != null) {
warn(`Slot "${key}" invoked outside of the render function: ` +
`this will not track dependencies used in the slot. ` +
`Invoke the slot function inside the render function instead.`);
}
return normalizeSlotValue(rawSlot(props));
};
function resolveSlots(instance, children) {
let slots;
if (instance.vnode.shapeFlag & 32 /* SLOTS_CHILDREN */) {
const rawSlots = children;
if (rawSlots._compiled) {
// pre-normalized slots object generated by compiler
slots = children;
}
else {
slots = {};
for (const key in rawSlots) {
if (key === '$stable')
continue;
const value = rawSlots[key];
if (isFunction(value)) {
slots[key] = normalizeSlot(key, value);
}
else if (value != null) {
if ((process.env.NODE_ENV !== 'production')) {
warn(`Non-function value encountered for slot "${key}". ` +
`Prefer function slots for better performance.`);
}
const normalized = normalizeSlotValue(value);
slots[key] = () => normalized;
}
}
}
}
else if (children !== null) {
// non slot object children (direct value) passed to a component
if ((process.env.NODE_ENV !== 'production') && !isKeepAlive(instance.vnode)) {
warn(`Non-function value encountered for default slot. ` +
`Prefer function slots for better performance.`);
}
const normalized = normalizeSlotValue(children);
slots = { default: () => normalized };
}
instance.slots = slots || EMPTY_OBJ;
}
/**
Runtime helper for applying directives to a vnode. Example usage:
const comp = resolveComponent('comp')
const foo = resolveDirective('foo')
const bar = resolveDirective('bar')
return withDirectives(h(comp), [
[foo, this.x],
[bar, this.y]
])
*/
const isBuiltInDirective = /*#__PURE__*/ makeMap('bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text');
function validateDirectiveName(name) {
if (isBuiltInDirective(name)) {
warn('Do not use built-in directive ids as custom directive id: ' + name);
}
}
const directiveToVnodeHooksMap = /*#__PURE__*/ [
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeUnmount',
'unmounted'
].reduce((map, key) => {
const vnodeKey = `onVnode` + key[0].toUpperCase() + key.slice(1);
const vnodeHook = (vnode, prevVnode) => {
const bindings = vnode.dirs;
const prevBindings = prevVnode ? prevVnode.dirs : EMPTY_ARR;
for (let i = 0; i < bindings.length; i++) {
const binding = bindings[i];
const hook = binding.dir[key];
if (hook != null) {
if (prevVnode != null) {
binding.oldValue = prevBindings[i].value;
}
hook(vnode.el, binding, vnode, prevVnode);
}
}
};
map[key] = [vnodeKey, vnodeHook];
return map;
}, {});
function withDirectives(vnode, directives) {
const internalInstance = currentRenderingInstance;
if (internalInstance === null) {
(process.env.NODE_ENV !== 'production') && warn(`withDirectives can only be used inside render functions.`);
return vnode;
}
const instance = internalInstance.proxy;
const props = vnode.props || (vnode.props = {});
const bindings = vnode.dirs || (vnode.dirs = new Array(directives.length));
const injected = {};
for (let i = 0; i < directives.length; i++) {
let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i];
if (isFunction(dir)) {
dir = {
mounted: dir,
updated: dir
};
}
bindings[i] = {
dir,
instance,
value,
oldValue: void 0,
arg,
modifiers
};
// inject onVnodeXXX hooks
for (const key in dir) {
if (!injected[key]) {
const { 0: hookName, 1: hook } = directiveToVnodeHooksMap[key];
const existing = props[hookName];
props[hookName] = existing ? [].concat(existing, hook) : hook;
injected[key] = true;
}
}
}
return vnode;
}
function invokeDirectiveHook(hook, instance, vnode, prevVNode = null) {
callWithAsyncErrorHandling(hook, instance, 7 /* DIRECTIVE_HOOK */, [
vnode,
prevVNode
]);
}
function createAppContext() {
return {
config: {
devtools: true,
performance: false,
isNativeTag: NO,
isCustomElement: NO,
errorHandler: undefined,
warnHandler: undefined
},
mixins: [],
components: {},
directives: {},
provides: {}
};
}
function createAppAPI(render) {
return function createApp() {
const context = createAppContext();
const installedPlugins = new Set();
let isMounted = false;
const app = {
get config() {
return context.config;
},
set config(v) {
if ((process.env.NODE_ENV !== 'production')) {
warn(`app.config cannot be replaced. Modify individual options instead.`);
}
},
use(plugin, ...options) {
if (installedPlugins.has(plugin)) {
(process.env.NODE_ENV !== 'production') && warn(`Plugin has already been applied to target app.`);
}
else if (isFunction(plugin)) {
installedPlugins.add(plugin);
plugin(app, ...options);
}
else if (plugin && isFunction(plugin.install)) {
installedPlugins.add(plugin);
plugin.install(app, ...options);
}
else if ((process.env.NODE_ENV !== 'production')) {
warn(`A plugin must either be a function or an object with an "install" ` +
`function.`);
}
return app;
},
mixin(mixin) {
if ((process.env.NODE_ENV !== 'production') && !true) {
warn('Mixins are only available in builds supporting Options API');
}
if (!context.mixins.includes(mixin)) {
context.mixins.push(mixin);
}
else if ((process.env.NODE_ENV !== 'production')) {
warn('Mixin has already been applied to target app' +
(mixin.name ? `: ${mixin.name}` : ''));
}
return app;
},
component(name, component) {
if ((process.env.NODE_ENV !== 'production')) {
validateComponentName(name, context.config);
}
if (!component) {
return context.components[name];
}
if ((process.env.NODE_ENV !== 'production') && context.components[name]) {
warn(`Component "${name}" has already been registered in target app.`);
}
context.components[name] = component;
return app;
},
directive(name, directive) {
if ((process.env.NODE_ENV !== 'production')) {
validateDirectiveName(name);
}
if (!directive) {
return context.directives[name];
}
if ((process.env.NODE_ENV !== 'production') && context.directives[name]) {
warn(`Directive "${name}" has already been registered in target app.`);
}
context.directives[name] = directive;
return app;
},
mount(rootComponent, rootContainer, rootProps) {
if (!isMounted) {
if (rootProps != null && !isObject(rootProps)) {
(process.env.NODE_ENV !== 'production') &&
warn(`root props pa