UNPKG

vue-next

Version:

## Status: Pre-Alpha.

1,495 lines (1,477 loc) 168 kB
// 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: 64 /* KEYED_FRAGMENT */, UNKEYED_FRAGMENT: 128 /* UNKEYED_FRAGMENT */, DYNAMIC_SLOTS: 256 /* DYNAMIC_SLOTS */, BAIL: -1 /* BAIL */ }; // 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]; } const EMPTY_OBJ = Object.freeze({}) ; const EMPTY_ARR = []; const NOOP = () => { }; /** * Always return false. */ const NO = () => false; const isOn = (key) => key[0] === 'o' && key[1] === 'n'; 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 isSymbol = (val) => typeof val === 'symbol'; 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 = (key) => key === 'key' || key === 'ref' || key.startsWith(`onVnode`); const camelizeRE = /-(\w)/g; const camelize = (str) => { return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); }; const hyphenateRE = /\B([A-Z])/g; const hyphenate = (str) => { return str.replace(hyphenateRE, '-$1').toLowerCase(); }; const capitalize = (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); // implementation, close to no-op function createComponent(options) { return isFunction(options) ? { setup: options } : options; } // global immutability lock let LOCKED = true; function lock() { LOCKED = true; } function unlock() { LOCKED = false; } const builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol) .map(key => Symbol[key]) .filter(isSymbol)); function createGetter(isReadonly) { return function get(target, key, receiver) { const res = Reflect.get(target, key, receiver); if (isSymbol(key) && builtInSymbols.has(key)) { return res; } if (isRef(res)) { return res.value; } track(target, "get" /* GET */, key); return isObject(res) ? isReadonly ? // need to lazy access readonly and reactive here to avoid // circular dependency readonly(res) : reactive(res) : res; }; } function set(target, key, value, receiver) { value = toRaw(value); const oldValue = target[key]; if (isRef(oldValue) && !isRef(value)) { oldValue.value = value; return true; } const hadKey = hasOwn(target, key); const result = Reflect.set(target, key, value, receiver); // don't trigger if target is something up in the prototype chain of original if (target === toRaw(receiver)) { /* istanbul ignore else */ { const extraInfo = { oldValue, newValue: value }; if (!hadKey) { trigger(target, "add" /* ADD */, key, extraInfo); } else if (hasChanged(value, oldValue)) { trigger(target, "set" /* SET */, key, extraInfo); } } } return result; } function deleteProperty(target, key) { const hadKey = hasOwn(target, key); const oldValue = target[key]; const result = Reflect.deleteProperty(target, key); if (result && hadKey) { /* istanbul ignore else */ { trigger(target, "delete" /* DELETE */, key, { oldValue }); } } return result; } function has(target, key) { const result = Reflect.has(target, key); track(target, "has" /* HAS */, key); return result; } function ownKeys(target) { track(target, "iterate" /* ITERATE */); return Reflect.ownKeys(target); } const mutableHandlers = { get: createGetter(false), set, deleteProperty, has, ownKeys }; const readonlyHandlers = { get: createGetter(true), set(target, key, value, receiver) { if (LOCKED) { { console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target); } return true; } else { return set(target, key, value, receiver); } }, deleteProperty(target, key) { if (LOCKED) { { console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target); } return true; } else { return deleteProperty(target, key); } }, has, ownKeys }; const toReactive = (value) => isObject(value) ? reactive(value) : value; const toReadonly = (value) => isObject(value) ? readonly(value) : value; const getProto = (v) => Reflect.getPrototypeOf(v); function get(target, key, wrap) { target = toRaw(target); key = toRaw(key); track(target, "get" /* GET */, key); return wrap(getProto(target).get.call(target, key)); } function has$1(key) { const target = toRaw(this); key = toRaw(key); track(target, "has" /* HAS */, key); return getProto(target).has.call(target, key); } function size(target) { target = toRaw(target); track(target, "iterate" /* ITERATE */); return Reflect.get(getProto(target), 'size', target); } function add(value) { value = toRaw(value); const target = toRaw(this); const proto = getProto(target); const hadKey = proto.has.call(target, value); const result = proto.add.call(target, value); if (!hadKey) { /* istanbul ignore else */ { trigger(target, "add" /* ADD */, value, { newValue: value }); } } return result; } function set$1(key, value) { value = toRaw(value); const target = toRaw(this); const proto = getProto(target); const hadKey = proto.has.call(target, key); const oldValue = proto.get.call(target, key); const result = proto.set.call(target, key, value); /* istanbul ignore else */ { const extraInfo = { oldValue, newValue: value }; if (!hadKey) { trigger(target, "add" /* ADD */, key, extraInfo); } else if (hasChanged(value, oldValue)) { trigger(target, "set" /* SET */, key, extraInfo); } } return result; } function deleteEntry(key) { const target = toRaw(this); const proto = getProto(target); const hadKey = proto.has.call(target, key); const oldValue = proto.get ? proto.get.call(target, key) : undefined; // forward the operation before queueing reactions const result = proto.delete.call(target, key); if (hadKey) { /* istanbul ignore else */ { trigger(target, "delete" /* DELETE */, key, { oldValue }); } } return result; } function clear() { const target = toRaw(this); const hadItems = target.size !== 0; const oldTarget = target instanceof Map ? new Map(target) : new Set(target) ; // forward the operation before queueing reactions const result = getProto(target).clear.call(target); if (hadItems) { /* istanbul ignore else */ { trigger(target, "clear" /* CLEAR */, void 0, { oldTarget }); } } return result; } function createForEach(isReadonly) { return function forEach(callback, thisArg) { const observed = this; const target = toRaw(observed); const wrap = isReadonly ? toReadonly : toReactive; track(target, "iterate" /* ITERATE */); // important: create sure the callback is // 1. invoked with the reactive map as `this` and 3rd arg // 2. the value received should be a corresponding reactive/readonly. function wrappedCallback(value, key) { return callback.call(observed, wrap(value), wrap(key), observed); } return getProto(target).forEach.call(target, wrappedCallback, thisArg); }; } function createIterableMethod(method, isReadonly) { return function (...args) { const target = toRaw(this); const isPair = method === 'entries' || (method === Symbol.iterator && target instanceof Map); const innerIterator = getProto(target)[method].apply(target, args); const wrap = isReadonly ? toReadonly : toReactive; track(target, "iterate" /* ITERATE */); // return a wrapped iterator which returns observed versions of the // values emitted from the real iterator return { // iterator protocol next() { const { value, done } = innerIterator.next(); return done ? { value, done } : { value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), done }; }, // iterable protocol [Symbol.iterator]() { return this; } }; }; } function createReadonlyMethod(method, type) { return function (...args) { if (LOCKED) { { const key = args[0] ? `on key "${args[0]}" ` : ``; console.warn(`${capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this)); } return type === "delete" /* DELETE */ ? false : this; } else { return method.apply(this, args); } }; } const mutableInstrumentations = { get(key) { return get(this, key, toReactive); }, get size() { return size(this); }, has: has$1, add, set: set$1, delete: deleteEntry, clear, forEach: createForEach(false) }; const readonlyInstrumentations = { get(key) { return get(this, key, toReadonly); }, get size() { return size(this); }, has: has$1, add: createReadonlyMethod(add, "add" /* ADD */), set: createReadonlyMethod(set$1, "set" /* SET */), delete: createReadonlyMethod(deleteEntry, "delete" /* DELETE */), clear: createReadonlyMethod(clear, "clear" /* CLEAR */), forEach: createForEach(true) }; const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]; iteratorMethods.forEach(method => { mutableInstrumentations[method] = createIterableMethod(method, false); readonlyInstrumentations[method] = createIterableMethod(method, true); }); function createInstrumentationGetter(instrumentations) { return (target, key, receiver) => Reflect.get(hasOwn(instrumentations, key) && key in target ? instrumentations : target, key, receiver); } const mutableCollectionHandlers = { get: createInstrumentationGetter(mutableInstrumentations) }; const readonlyCollectionHandlers = { get: createInstrumentationGetter(readonlyInstrumentations) }; const targetMap = new WeakMap(); // WeakMaps that store {raw <-> observed} pairs. const rawToReactive = new WeakMap(); const reactiveToRaw = new WeakMap(); const rawToReadonly = new WeakMap(); const readonlyToRaw = new WeakMap(); // WeakSets for values that are marked readonly or non-reactive during // observable creation. const readonlyValues = new WeakSet(); const nonReactiveValues = new WeakSet(); const collectionTypes = new Set([Set, Map, WeakMap, WeakSet]); const isObservableType = /*#__PURE__*/ makeMap('Object,Array,Map,Set,WeakMap,WeakSet'); const canObserve = (value) => { return (!value._isVue && !value._isVNode && isObservableType(toRawType(value)) && !nonReactiveValues.has(value)); }; function reactive(target) { // if trying to observe a readonly proxy, return the readonly version. if (readonlyToRaw.has(target)) { return target; } // target is explicitly marked as readonly by user if (readonlyValues.has(target)) { return readonly(target); } return createReactiveObject(target, rawToReactive, reactiveToRaw, mutableHandlers, mutableCollectionHandlers); } function readonly(target) { // value is a mutable observable, retrieve its original and return // a readonly version. if (reactiveToRaw.has(target)) { target = reactiveToRaw.get(target); } return createReactiveObject(target, rawToReadonly, readonlyToRaw, readonlyHandlers, readonlyCollectionHandlers); } function createReactiveObject(target, toProxy, toRaw, baseHandlers, collectionHandlers) { if (!isObject(target)) { { console.warn(`value cannot be made reactive: ${String(target)}`); } return target; } // target already has corresponding Proxy let observed = toProxy.get(target); if (observed !== void 0) { return observed; } // target is already a Proxy if (toRaw.has(target)) { return target; } // only a whitelist of value types can be observed. if (!canObserve(target)) { return target; } const handlers = collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers; observed = new Proxy(target, handlers); toProxy.set(target, observed); toRaw.set(observed, target); if (!targetMap.has(target)) { targetMap.set(target, new Map()); } return observed; } function isReactive(value) { return reactiveToRaw.has(value) || readonlyToRaw.has(value); } function isReadonly(value) { return readonlyToRaw.has(value); } function toRaw(observed) { return reactiveToRaw.get(observed) || readonlyToRaw.get(observed) || observed; } function markReadonly(value) { readonlyValues.add(value); return value; } function markNonReactive(value) { nonReactiveValues.add(value); return value; } const effectStack = []; const ITERATE_KEY = Symbol('iterate'); function isEffect(fn) { return fn != null && fn._isEffect === true; } function effect(fn, options = EMPTY_OBJ) { if (isEffect(fn)) { fn = fn.raw; } const effect = createReactiveEffect(fn, options); if (!options.lazy) { effect(); } return effect; } function stop(effect) { if (effect.active) { cleanup(effect); if (effect.onStop) { effect.onStop(); } effect.active = false; } } function createReactiveEffect(fn, options) { const effect = function reactiveEffect(...args) { return run(effect, fn, args); }; effect._isEffect = true; effect.active = true; effect.raw = fn; effect.scheduler = options.scheduler; effect.onTrack = options.onTrack; effect.onTrigger = options.onTrigger; effect.onStop = options.onStop; effect.computed = options.computed; effect.deps = []; return effect; } function run(effect, fn, args) { if (!effect.active) { return fn(...args); } if (!effectStack.includes(effect)) { cleanup(effect); try { effectStack.push(effect); return fn(...args); } finally { effectStack.pop(); } } } function cleanup(effect) { const { deps } = effect; if (deps.length) { for (let i = 0; i < deps.length; i++) { deps[i].delete(effect); } deps.length = 0; } } let shouldTrack = true; function pauseTracking() { shouldTrack = false; } function resumeTracking() { shouldTrack = true; } function track(target, type, key) { if (!shouldTrack || effectStack.length === 0) { return; } const effect = effectStack[effectStack.length - 1]; if (type === "iterate" /* ITERATE */) { key = ITERATE_KEY; } let depsMap = targetMap.get(target); if (depsMap === void 0) { targetMap.set(target, (depsMap = new Map())); } let dep = depsMap.get(key); if (dep === void 0) { depsMap.set(key, (dep = new Set())); } if (!dep.has(effect)) { dep.add(effect); effect.deps.push(dep); if ( effect.onTrack) { effect.onTrack({ effect, target, type, key }); } } } function trigger(target, type, key, extraInfo) { const depsMap = targetMap.get(target); if (depsMap === void 0) { // never been tracked return; } const effects = new Set(); const computedRunners = new Set(); if (type === "clear" /* CLEAR */) { // collection being cleared, trigger all effects for target depsMap.forEach(dep => { addRunners(effects, computedRunners, dep); }); } else { // schedule runs for SET | ADD | DELETE if (key !== void 0) { addRunners(effects, computedRunners, depsMap.get(key)); } // also run for iteration key on ADD | DELETE if (type === "add" /* ADD */ || type === "delete" /* DELETE */) { const iterationKey = Array.isArray(target) ? 'length' : ITERATE_KEY; addRunners(effects, computedRunners, depsMap.get(iterationKey)); } } const run = (effect) => { scheduleRun(effect, target, type, key, extraInfo); }; // Important: computed effects must be run first so that computed getters // can be invalidated before any normal effects that depend on them are run. computedRunners.forEach(run); effects.forEach(run); } function addRunners(effects, computedRunners, effectsToAdd) { if (effectsToAdd !== void 0) { effectsToAdd.forEach(effect => { if (effect.computed) { computedRunners.add(effect); } else { effects.add(effect); } }); } } function scheduleRun(effect, target, type, key, extraInfo) { if ( effect.onTrigger) { const event = { effect, target, key, type }; effect.onTrigger(extraInfo ? extend(event, extraInfo) : event); } if (effect.scheduler !== void 0) { effect.scheduler(effect); } else { effect(); } } const convert = (val) => isObject(val) ? reactive(val) : val; function ref(raw) { if (isRef(raw)) { return raw; } raw = convert(raw); const r = { _isRef: true, get value() { track(r, "get" /* GET */, ''); return raw; }, set value(newVal) { raw = convert(newVal); trigger(r, "set" /* SET */, ''); } }; return r; } function isRef(r) { return r ? r._isRef === true : false; } function toRefs(object) { const ret = {}; for (const key in object) { ret[key] = toProxyRef(object, key); } return ret; } function toProxyRef(object, key) { return { _isRef: true, get value() { return object[key]; }, set value(newVal) { object[key] = newVal; } }; } function computed(getterOrOptions) { let getter; let setter; if (isFunction(getterOrOptions)) { getter = getterOrOptions; setter = () => { console.warn('Write operation failed: computed value is readonly'); } ; } else { getter = getterOrOptions.get; setter = getterOrOptions.set; } let dirty = true; let value; const runner = effect(getter, { lazy: true, // mark effect as computed so that it gets priority during trigger computed: true, scheduler: () => { dirty = true; } }); return { _isRef: true, // expose effect so computed can be stopped effect: runner, get value() { if (dirty) { value = runner(); dirty = false; } // When computed effects are accessed in a parent effect, the parent // should track all the dependencies the computed property has tracked. // This should also apply for chained computed properties. trackChildRun(runner); return value; }, set value(newValue) { setter(newValue); } }; } function trackChildRun(childRunner) { if (effectStack.length === 0) { return; } const parentRunner = effectStack[effectStack.length - 1]; for (let i = 0; i < childRunner.deps.length; i++) { const dep = childRunner.deps[i]; if (!dep.has(parentRunner)) { dep.add(parentRunner); parentRunner.deps.push(dep); } } } const stack = []; function pushWarningContext(vnode) { stack.push(vnode); } function popWarningContext() { stack.pop(); } function warn(msg, ...args) { const instance = stack.length ? stack[stack.length - 1].component : null; const appWarnHandler = instance && instance.appContext.config.warnHandler; const trace = getComponentTrace(); if (appWarnHandler) { appWarnHandler(msg + args.join(''), instance && instance.renderProxy, formatTrace(trace).join('')); return; } console.warn(`[Vue warn]: ${msg}`, ...args); // avoid spamming console during tests if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') { return; } if (!trace.length) { return; } if (trace.length > 1 && console.groupCollapsed) { console.groupCollapsed('at', ...formatTraceEntry(trace[0])); const logs = []; trace.slice(1).forEach((entry, i) => { if (i !== 0) logs.push('\n'); logs.push(...formatTraceEntry(entry, i + 1)); }); console.log(...logs); console.groupEnd(); } else { console.log(...formatTrace(trace)); } } 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) => { const formatted = formatTraceEntry(entry, i); if (i === 0) { logs.push('at', ...formatted); } else { logs.push('\n', ...formatted); } }); return logs; } function formatTraceEntry({ vnode, recurseCount }, depth = 0) { const padding = depth === 0 ? '' : ' '.repeat(depth * 2 + 1); const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``; const open = padding + `<${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; if (!name && file) { const match = file.match(/([^/\\]+)\.vue$/); if (match) { name = match[1]; } } return name ? classify(name) : 'AnonymousComponent'; } function formatProps(props) { const res = []; for (const key in props) { const value = props[key]; if (isString(value)) { res.push(`${key}=${JSON.stringify(value)}`); } else { res.push(`${key}=`, String(toRaw(value))); } } return res; } 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 /* APP_ERROR_HANDLER */]: 'app errorHandler', [9 /* APP_WARN_HANDLER */]: 'app warnHandler', [10 /* 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.renderProxy; // in production the hook receives only the error code const errorInfo = ErrorTypeStrings[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, 8 /* APP_ERROR_HANDLER */, [err, exposedInstance, errorInfo]); return; } } logError(err, type, contextVNode); } function logError(err, type, contextVNode) { // default behavior is crash in prod & test, recover in dev. if ( !(typeof process !== 'undefined' && 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 queue = []; const postFlushCbs = []; const p = Promise.resolve(); let isFlushing = false; function nextTick(fn) { return fn ? p.then(fn) : p; } function queueJob(job) { if (!queue.includes(job)) { queue.push(job); if (!isFlushing) { nextTick(flushJobs); } } } function queuePostFlushCb(cb) { if (!isArray(cb)) { postFlushCbs.push(cb); } else { postFlushCbs.push(...cb); } if (!isFlushing) { nextTick(flushJobs); } } const dedupe = (cbs) => [...new Set(cbs)]; function flushPostFlushCbs() { if (postFlushCbs.length) { const cbs = dedupe(postFlushCbs); postFlushCbs.length = 0; for (let i = 0; i < cbs.length; i++) { cbs[i](); } } } const RECURSION_LIMIT = 100; function flushJobs(seenJobs) { isFlushing = true; let job; { seenJobs = seenJobs || new Map(); } while ((job = queue.shift())) { { const seen = seenJobs; if (!seen.has(job)) { seen.set(job, 1); } else { const count = seen.get(job); 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.'); } else { seen.set(job, count + 1); } } } callWithErrorHandling(job, null, 10 /* SCHEDULER */); } flushPostFlushCbs(); isFlushing = false; // some postFlushCb queued jobs! // keep flushing until it drains. if (queue.length) { flushJobs(seenJobs); } } const Fragment = Symbol( 'Fragment' ); const Portal = Symbol( 'Portal' ); const Suspense = Symbol( 'Suspense' ); const Text = Symbol( 'Text' ); const Comment = Symbol( 'Comment' ); // 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 = 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$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. function createBlock(type, props, children, patchFlag, dynamicProps) { // avoid a block with patchFlag tracking itself shouldTrack$1--; const vnode = createVNode(type, props, children, patchFlag, dynamicProps); shouldTrack$1++; // 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 createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null) { // 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 */ : 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, children: null, component: null, suspense: 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$1 > 0 && currentBlock !== null && (patchFlag > 0 || shapeFlag & 4 /* STATEFUL_COMPONENT */ || shapeFlag & 2 /* FUNCTIONAL_COMPONENT */)) { currentBlock.push(vnode); } return vnode; } function cloneVNode(vnode, extraProps) { return { _isVNode: true, type: vnode.type, props: extraProps ? vnode.props ? mergeProps(vnode.props, extraProps) : extraProps : vnode.props, key: vnode.key, ref: vnode.ref, children: vnode.children, target: vnode.target, shapeFlag: vnode.shapeFlag, patchFlag: vnode.patchFlag, dynamicProps: vnode.dynamicProps, dynamicChildren: vnode.dynamicChildren, appContext: vnode.appContext, // these should be set to null since they should only be present on // mounted VNodes. If they are somehow not null, this means we have // encountered an already-mounted vnode being used again. component: null, suspense: null, el: null, anchor: null }; } 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, 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 = isString(children) ? children : 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; } function injectHook(type, hook, target) { if (target) { (target[type] || (target[type] = [])).push((...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); resumeTracking(); return res; }); } else { 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) => 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 = createHook("ec" /* ERROR_CAPTURED */); // 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, renderProxy, props, slots, attrs, emit } = instance; let result; currentRenderingInstance = instance; { accessedAttrs = false; } try { if (vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */) { result = normalizeVNode(instance.render.call(renderProxy)); } 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 (true && !accessedAttrs) { warn(`Extraneous non-props attributes (${Object.keys(attrs).join(',')}) ` + `were passed to component but could not be automatically inhertied ` + `because component renders fragment or text root nodes.`); } } } catch (err) { handleError(err, instance, 1 /* RENDER_FUNCTION */); result = createVNode(Comment); } currentRenderingInstance = null; return result; } function shouldUpdateComponent(prevVNode, nextVNode, optimized) { const { props: prevProps, children: prevChildren } = prevVNode; const { props: nextProps, children: nextChildren, patchFlag } = nextVNode; if (patchFlag > 0) { if (patchFlag & 256 /* 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) { 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; } // 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; const options = normalizePropsOptions(_options); if (!rawProps && !hasDeclaredProps) { return; } 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 if (isReservedProp(key)) 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]); } } } // set default values, cast booleans & run validators if (hasDeclaredProps) { for (const key in options) { 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["1" /* shouldCast */]) { if (isAbsent && !hasDefault) {