vue
Version:
Reactive, component-oriented view layer for modern web interfaces.
1,711 lines (1,693 loc) • 290 kB
JavaScript
/*!
* Vue.js v2.7.14
* (c) 2014-2022 Evan You
* Released under the MIT License.
*/
'use strict';
const emptyObject = Object.freeze({});
const isArray = Array.isArray;
// These helpers produce better VM code in JS engines due to their
// explicitness and function inlining.
function isUndef(v) {
return v === undefined || v === null;
}
function isDef(v) {
return v !== undefined && v !== null;
}
function isTrue(v) {
return v === true;
}
function isFalse(v) {
return v === false;
}
/**
* Check if value is primitive.
*/
function isPrimitive(value) {
return (typeof value === 'string' ||
typeof value === 'number' ||
// $flow-disable-line
typeof value === 'symbol' ||
typeof value === 'boolean');
}
function isFunction(value) {
return typeof value === 'function';
}
/**
* Quick object check - this is primarily used to tell
* objects from primitive values when we know the value
* is a JSON-compliant type.
*/
function isObject(obj) {
return obj !== null && typeof obj === 'object';
}
/**
* Get the raw type string of a value, e.g., [object Object].
*/
const _toString = Object.prototype.toString;
function toRawType(value) {
return _toString.call(value).slice(8, -1);
}
/**
* Strict object type check. Only returns true
* for plain JavaScript objects.
*/
function isPlainObject(obj) {
return _toString.call(obj) === '[object Object]';
}
function isRegExp(v) {
return _toString.call(v) === '[object RegExp]';
}
/**
* Check if val is a valid array index.
*/
function isValidArrayIndex(val) {
const n = parseFloat(String(val));
return n >= 0 && Math.floor(n) === n && isFinite(val);
}
function isPromise(val) {
return (isDef(val) &&
typeof val.then === 'function' &&
typeof val.catch === 'function');
}
/**
* Convert a value to a string that is actually rendered.
*/
function toString(val) {
return val == null
? ''
: Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
? JSON.stringify(val, null, 2)
: String(val);
}
/**
* Convert an input value to a number for persistence.
* If the conversion fails, return original string.
*/
function toNumber(val) {
const n = parseFloat(val);
return isNaN(n) ? val : n;
}
/**
* Make a map and return a function for checking if a key
* is in that map.
*/
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];
}
/**
* Check if a tag is a built-in tag.
*/
const isBuiltInTag = makeMap('slot,component', true);
/**
* Check if an attribute is a reserved attribute.
*/
const isReservedAttribute = makeMap('key,ref,slot,slot-scope,is');
/**
* Remove an item from an array.
*/
function remove$2(arr, item) {
const len = arr.length;
if (len) {
// fast path for the only / last item
if (item === arr[len - 1]) {
arr.length = len - 1;
return;
}
const index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1);
}
}
}
/**
* Check whether an object has the property.
*/
const hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
return hasOwnProperty.call(obj, key);
}
/**
* Create a cached version of a pure function.
*/
function cached(fn) {
const cache = Object.create(null);
return function cachedFn(str) {
const hit = cache[str];
return hit || (cache[str] = fn(str));
};
}
/**
* Camelize a hyphen-delimited string.
*/
const camelizeRE = /-(\w)/g;
const camelize = cached((str) => {
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
});
/**
* Capitalize a string.
*/
const capitalize = cached((str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
});
/**
* Hyphenate a camelCase string.
*/
const hyphenateRE = /\B([A-Z])/g;
const hyphenate = cached((str) => {
return str.replace(hyphenateRE, '-$1').toLowerCase();
});
/**
* Simple bind polyfill for environments that do not support it,
* e.g., PhantomJS 1.x. Technically, we don't need this anymore
* since native bind is now performant enough in most browsers.
* But removing it would mean breaking code that was able to run in
* PhantomJS 1.x, so this must be kept for backward compatibility.
*/
/* istanbul ignore next */
function polyfillBind(fn, ctx) {
function boundFn(a) {
const l = arguments.length;
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx);
}
boundFn._length = fn.length;
return boundFn;
}
function nativeBind(fn, ctx) {
return fn.bind(ctx);
}
// @ts-expect-error bind cannot be `undefined`
const bind = Function.prototype.bind ? nativeBind : polyfillBind;
/**
* Convert an Array-like object to a real Array.
*/
function toArray(list, start) {
start = start || 0;
let i = list.length - start;
const ret = new Array(i);
while (i--) {
ret[i] = list[i + start];
}
return ret;
}
/**
* Mix properties into target object.
*/
function extend(to, _from) {
for (const key in _from) {
to[key] = _from[key];
}
return to;
}
/**
* Merge an Array of Objects into a single Object.
*/
function toObject(arr) {
const res = {};
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res;
}
/* eslint-disable no-unused-vars */
/**
* Perform no operation.
* Stubbing args to make Flow happy without leaving useless transpiled code
* with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/).
*/
function noop(a, b, c) { }
/**
* Always return false.
*/
const no = (a, b, c) => false;
/* eslint-enable no-unused-vars */
/**
* Return the same value.
*/
const identity = (_) => _;
/**
* Check if two values are loosely equal - that is,
* if they are plain objects, do they have the same shape?
*/
function looseEqual(a, b) {
if (a === b)
return true;
const isObjectA = isObject(a);
const isObjectB = isObject(b);
if (isObjectA && isObjectB) {
try {
const isArrayA = Array.isArray(a);
const isArrayB = Array.isArray(b);
if (isArrayA && isArrayB) {
return (a.length === b.length &&
a.every((e, i) => {
return looseEqual(e, b[i]);
}));
}
else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime();
}
else if (!isArrayA && !isArrayB) {
const keysA = Object.keys(a);
const keysB = Object.keys(b);
return (keysA.length === keysB.length &&
keysA.every(key => {
return looseEqual(a[key], b[key]);
}));
}
else {
/* istanbul ignore next */
return false;
}
}
catch (e) {
/* istanbul ignore next */
return false;
}
}
else if (!isObjectA && !isObjectB) {
return String(a) === String(b);
}
else {
return false;
}
}
/**
* Return the first index at which a loosely equal value can be
* found in the array (if value is a plain object, the array must
* contain an object of the same shape), or -1 if it is not present.
*/
function looseIndexOf(arr, val) {
for (let i = 0; i < arr.length; i++) {
if (looseEqual(arr[i], val))
return i;
}
return -1;
}
/**
* Ensure a function is called only once.
*/
function once(fn) {
let called = false;
return function () {
if (!called) {
called = true;
fn.apply(this, arguments);
}
};
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#polyfill
function hasChanged(x, y) {
if (x === y) {
return x === 0 && 1 / x !== 1 / y;
}
else {
return x === x || y === y;
}
}
const SSR_ATTR = 'data-server-rendered';
const ASSET_TYPES = ['component', 'directive', 'filter'];
const LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
'activated',
'deactivated',
'errorCaptured',
'serverPrefetch',
'renderTracked',
'renderTriggered'
];
var config = {
/**
* Option merge strategies (used in core/util/options)
*/
// $flow-disable-line
optionMergeStrategies: Object.create(null),
/**
* Whether to suppress warnings.
*/
silent: false,
/**
* Show production mode tip message on boot?
*/
productionTip: true,
/**
* Whether to enable devtools
*/
devtools: true,
/**
* Whether to record perf
*/
performance: false,
/**
* Error handler for watcher errors
*/
errorHandler: null,
/**
* Warn handler for watcher warns
*/
warnHandler: null,
/**
* Ignore certain custom elements
*/
ignoredElements: [],
/**
* Custom user key aliases for v-on
*/
// $flow-disable-line
keyCodes: Object.create(null),
/**
* Check if a tag is reserved so that it cannot be registered as a
* component. This is platform-dependent and may be overwritten.
*/
isReservedTag: no,
/**
* Check if an attribute is reserved so that it cannot be used as a component
* prop. This is platform-dependent and may be overwritten.
*/
isReservedAttr: no,
/**
* Check if a tag is an unknown element.
* Platform-dependent.
*/
isUnknownElement: no,
/**
* Get the namespace of an element
*/
getTagNamespace: noop,
/**
* Parse the real tag name for the specific platform.
*/
parsePlatformTagName: identity,
/**
* Check if an attribute must be bound using property, e.g. value
* Platform-dependent.
*/
mustUseProp: no,
/**
* Perform updates asynchronously. Intended to be used by Vue Test Utils
* This will significantly reduce performance if set to false.
*/
async: true,
/**
* Exposed for legacy reasons
*/
_lifecycleHooks: LIFECYCLE_HOOKS
};
/**
* unicode letters used for parsing html tags, component names and property paths.
* using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname
* skipping \u10000-\uEFFFF due to it freezing up PhantomJS
*/
const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/;
/**
* Check if a string starts with $ or _
*/
function isReserved(str) {
const c = (str + '').charCodeAt(0);
return c === 0x24 || c === 0x5f;
}
/**
* Define a property.
*/
function def(obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
/**
* Parse simple path.
*/
const bailRE = new RegExp(`[^${unicodeRegExp.source}.$_\\d]`);
function parsePath(path) {
if (bailRE.test(path)) {
return;
}
const segments = path.split('.');
return function (obj) {
for (let i = 0; i < segments.length; i++) {
if (!obj)
return;
obj = obj[segments[i]];
}
return obj;
};
}
// can we use __proto__?
const hasProto = '__proto__' in {};
// Browser environment sniffing
const inBrowser = typeof window !== 'undefined';
const UA = inBrowser && window.navigator.userAgent.toLowerCase();
const isIE = UA && /msie|trident/.test(UA);
const isIE9 = UA && UA.indexOf('msie 9.0') > 0;
const isEdge = UA && UA.indexOf('edge/') > 0;
UA && UA.indexOf('android') > 0;
const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA);
UA && /chrome\/\d+/.test(UA) && !isEdge;
UA && /phantomjs/.test(UA);
const isFF = UA && UA.match(/firefox\/(\d+)/);
// Firefox has a "watch" function on Object.prototype...
// @ts-expect-error firebox support
const nativeWatch = {}.watch;
let supportsPassive = false;
if (inBrowser) {
try {
const opts = {};
Object.defineProperty(opts, 'passive', {
get() {
/* istanbul ignore next */
supportsPassive = true;
}
}); // https://github.com/facebook/flow/issues/285
window.addEventListener('test-passive', null, opts);
}
catch (e) { }
}
// this needs to be lazy-evaled because vue may be required before
// vue-server-renderer can set VUE_ENV
let _isServer;
const isServerRendering = () => {
if (_isServer === undefined) {
/* istanbul ignore if */
if (!inBrowser && typeof global !== 'undefined') {
// detect presence of vue-server-renderer and avoid
// Webpack shimming the process
_isServer =
global['process'] && global['process'].env.VUE_ENV === 'server';
}
else {
_isServer = false;
}
}
return _isServer;
};
// detect devtools
const devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
/* istanbul ignore next */
function isNative(Ctor) {
return typeof Ctor === 'function' && /native code/.test(Ctor.toString());
}
const hasSymbol = typeof Symbol !== 'undefined' &&
isNative(Symbol) &&
typeof Reflect !== 'undefined' &&
isNative(Reflect.ownKeys);
let _Set; // $flow-disable-line
/* istanbul ignore if */ if (typeof Set !== 'undefined' && isNative(Set)) {
// use native Set when available.
_Set = Set;
}
else {
// a non-standard Set polyfill that only works with primitive keys.
_Set = class Set {
constructor() {
this.set = Object.create(null);
}
has(key) {
return this.set[key] === true;
}
add(key) {
this.set[key] = true;
}
clear() {
this.set = Object.create(null);
}
};
}
let currentInstance = null;
/**
* This is exposed for compatibility with v3 (e.g. some functions in VueUse
* relies on it). Do not use this internally, just use `currentInstance`.
*
* @internal this function needs manual type declaration because it relies
* on previously manually authored types from Vue 2
*/
function getCurrentInstance() {
return currentInstance && { proxy: currentInstance };
}
/**
* @internal
*/
function setCurrentInstance(vm = null) {
if (!vm)
currentInstance && currentInstance._scope.off();
currentInstance = vm;
vm && vm._scope.on();
}
/**
* @internal
*/
class VNode {
constructor(tag, data, children, text, elm, context, componentOptions, asyncFactory) {
this.tag = tag;
this.data = data;
this.children = children;
this.text = text;
this.elm = elm;
this.ns = undefined;
this.context = context;
this.fnContext = undefined;
this.fnOptions = undefined;
this.fnScopeId = undefined;
this.key = data && data.key;
this.componentOptions = componentOptions;
this.componentInstance = undefined;
this.parent = undefined;
this.raw = false;
this.isStatic = false;
this.isRootInsert = true;
this.isComment = false;
this.isCloned = false;
this.isOnce = false;
this.asyncFactory = asyncFactory;
this.asyncMeta = undefined;
this.isAsyncPlaceholder = false;
}
// DEPRECATED: alias for componentInstance for backwards compat.
/* istanbul ignore next */
get child() {
return this.componentInstance;
}
}
const createEmptyVNode = (text = '') => {
const node = new VNode();
node.text = text;
node.isComment = true;
return node;
};
function createTextVNode(val) {
return new VNode(undefined, undefined, undefined, String(val));
}
// optimized shallow clone
// used for static nodes and slot nodes because they may be reused across
// multiple renders, cloning them avoids errors when DOM manipulations rely
// on their elm reference.
function cloneVNode(vnode) {
const cloned = new VNode(vnode.tag, vnode.data,
// #7975
// clone children array to avoid mutating original in case of cloning
// a child.
vnode.children && vnode.children.slice(), vnode.text, vnode.elm, vnode.context, vnode.componentOptions, vnode.asyncFactory);
cloned.ns = vnode.ns;
cloned.isStatic = vnode.isStatic;
cloned.key = vnode.key;
cloned.isComment = vnode.isComment;
cloned.fnContext = vnode.fnContext;
cloned.fnOptions = vnode.fnOptions;
cloned.fnScopeId = vnode.fnScopeId;
cloned.asyncMeta = vnode.asyncMeta;
cloned.isCloned = true;
return cloned;
}
let uid$2 = 0;
const pendingCleanupDeps = [];
const cleanupDeps = () => {
for (let i = 0; i < pendingCleanupDeps.length; i++) {
const dep = pendingCleanupDeps[i];
dep.subs = dep.subs.filter(s => s);
dep._pending = false;
}
pendingCleanupDeps.length = 0;
};
/**
* A dep is an observable that can have multiple
* directives subscribing to it.
* @internal
*/
class Dep {
constructor() {
// pending subs cleanup
this._pending = false;
this.id = uid$2++;
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
removeSub(sub) {
// #12696 deps with massive amount of subscribers are extremely slow to
// clean up in Chromium
// to workaround this, we unset the sub for now, and clear them on
// next scheduler flush.
this.subs[this.subs.indexOf(sub)] = null;
if (!this._pending) {
this._pending = true;
pendingCleanupDeps.push(this);
}
}
depend(info) {
if (Dep.target) {
Dep.target.addDep(this);
if (info && Dep.target.onTrack) {
Dep.target.onTrack(Object.assign({ effect: Dep.target }, info));
}
}
}
notify(info) {
// stabilize the subscriber list first
const subs = this.subs.filter(s => s);
if (!config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort((a, b) => a.id - b.id);
}
for (let i = 0, l = subs.length; i < l; i++) {
const sub = subs[i];
if (info) {
sub.onTrigger &&
sub.onTrigger(Object.assign({ effect: subs[i] }, info));
}
sub.update();
}
}
}
// The current target watcher being evaluated.
// This is globally unique because only one watcher
// can be evaluated at a time.
Dep.target = null;
const targetStack = [];
function pushTarget(target) {
targetStack.push(target);
Dep.target = target;
}
function popTarget() {
targetStack.pop();
Dep.target = targetStack[targetStack.length - 1];
}
/*
* not type checking this file because flow doesn't play well with
* dynamically accessing methods on Array prototype
*/
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
];
/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method];
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args);
const ob = this.__ob__;
let inserted;
switch (method) {
case 'push':
case 'unshift':
inserted = args;
break;
case 'splice':
inserted = args.slice(2);
break;
}
if (inserted)
ob.observeArray(inserted);
// notify change
{
ob.dep.notify({
type: "array mutation" /* TriggerOpTypes.ARRAY_MUTATION */,
target: this,
key: method
});
}
return result;
});
});
const arrayKeys = Object.getOwnPropertyNames(arrayMethods);
const NO_INIITIAL_VALUE = {};
/**
* In some cases we may want to disable observation inside a component's
* update computation.
*/
let shouldObserve = true;
function toggleObserving(value) {
shouldObserve = value;
}
// ssr mock dep
const mockDep = {
notify: noop,
depend: noop,
addSub: noop,
removeSub: noop
};
/**
* Observer class that is attached to each observed
* object. Once attached, the observer converts the target
* object's property keys into getter/setters that
* collect dependencies and dispatch updates.
*/
class Observer {
constructor(value, shallow = false, mock = false) {
this.value = value;
this.shallow = shallow;
this.mock = mock;
// this.value = value
this.dep = mock ? mockDep : new Dep();
this.vmCount = 0;
def(value, '__ob__', this);
if (isArray(value)) {
if (!mock) {
if (hasProto) {
value.__proto__ = arrayMethods;
/* eslint-enable no-proto */
}
else {
for (let i = 0, l = arrayKeys.length; i < l; i++) {
const key = arrayKeys[i];
def(value, key, arrayMethods[key]);
}
}
}
if (!shallow) {
this.observeArray(value);
}
}
else {
/**
* Walk through all properties and convert them into
* getter/setters. This method should only be called when
* value type is Object.
*/
const keys = Object.keys(value);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
defineReactive(value, key, NO_INIITIAL_VALUE, undefined, shallow, mock);
}
}
}
/**
* Observe a list of Array items.
*/
observeArray(value) {
for (let i = 0, l = value.length; i < l; i++) {
observe(value[i], false, this.mock);
}
}
}
// helpers
/**
* Attempt to create an observer instance for a value,
* returns the new observer if successfully observed,
* or the existing observer if the value already has one.
*/
function observe(value, shallow, ssrMockReactivity) {
if (value && hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
return value.__ob__;
}
if (shouldObserve &&
(ssrMockReactivity || !isServerRendering()) &&
(isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value.__v_skip /* ReactiveFlags.SKIP */ &&
!isRef(value) &&
!(value instanceof VNode)) {
return new Observer(value, shallow, ssrMockReactivity);
}
}
/**
* Define a reactive property on an Object.
*/
function defineReactive(obj, key, val, customSetter, shallow, mock) {
const dep = new Dep();
const property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return;
}
// cater for pre-defined getter/setters
const getter = property && property.get;
const setter = property && property.set;
if ((!getter || setter) &&
(val === NO_INIITIAL_VALUE || arguments.length === 2)) {
val = obj[key];
}
let childOb = !shallow && observe(val, false, mock);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = getter ? getter.call(obj) : val;
if (Dep.target) {
{
dep.depend({
target: obj,
type: "get" /* TrackOpTypes.GET */,
key
});
}
if (childOb) {
childOb.dep.depend();
if (isArray(value)) {
dependArray(value);
}
}
}
return isRef(value) && !shallow ? value.value : value;
},
set: function reactiveSetter(newVal) {
const value = getter ? getter.call(obj) : val;
if (!hasChanged(value, newVal)) {
return;
}
if (customSetter) {
customSetter();
}
if (setter) {
setter.call(obj, newVal);
}
else if (getter) {
// #7981: for accessor properties without setter
return;
}
else if (!shallow && isRef(value) && !isRef(newVal)) {
value.value = newVal;
return;
}
else {
val = newVal;
}
childOb = !shallow && observe(newVal, false, mock);
{
dep.notify({
type: "set" /* TriggerOpTypes.SET */,
target: obj,
key,
newValue: newVal,
oldValue: value
});
}
}
});
return dep;
}
function set(target, key, val) {
if ((isUndef(target) || isPrimitive(target))) {
warn(`Cannot set reactive property on undefined, null, or primitive value: ${target}`);
}
if (isReadonly(target)) {
warn(`Set operation on key "${key}" failed: target is readonly.`);
return;
}
const ob = target.__ob__;
if (isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key);
target.splice(key, 1, val);
// when mocking for SSR, array methods are not hijacked
if (ob && !ob.shallow && ob.mock) {
observe(val, false, true);
}
return val;
}
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val;
}
if (target._isVue || (ob && ob.vmCount)) {
warn('Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.');
return val;
}
if (!ob) {
target[key] = val;
return val;
}
defineReactive(ob.value, key, val, undefined, ob.shallow, ob.mock);
{
ob.dep.notify({
type: "add" /* TriggerOpTypes.ADD */,
target: target,
key,
newValue: val,
oldValue: undefined
});
}
return val;
}
function del(target, key) {
if ((isUndef(target) || isPrimitive(target))) {
warn(`Cannot delete reactive property on undefined, null, or primitive value: ${target}`);
}
if (isArray(target) && isValidArrayIndex(key)) {
target.splice(key, 1);
return;
}
const ob = target.__ob__;
if (target._isVue || (ob && ob.vmCount)) {
warn('Avoid deleting properties on a Vue instance or its root $data ' +
'- just set it to null.');
return;
}
if (isReadonly(target)) {
warn(`Delete operation on key "${key}" failed: target is readonly.`);
return;
}
if (!hasOwn(target, key)) {
return;
}
delete target[key];
if (!ob) {
return;
}
{
ob.dep.notify({
type: "delete" /* TriggerOpTypes.DELETE */,
target: target,
key
});
}
}
/**
* Collect dependencies on array elements when the array is touched, since
* we cannot intercept array element access like property getters.
*/
function dependArray(value) {
for (let e, i = 0, l = value.length; i < l; i++) {
e = value[i];
if (e && e.__ob__) {
e.__ob__.dep.depend();
}
if (isArray(e)) {
dependArray(e);
}
}
}
function reactive(target) {
makeReactive(target, false);
return target;
}
/**
* Return a shallowly-reactive copy of the original object, where only the root
* level properties are reactive. It also does not auto-unwrap refs (even at the
* root level).
*/
function shallowReactive(target) {
makeReactive(target, true);
def(target, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, true);
return target;
}
function makeReactive(target, shallow) {
// if trying to observe a readonly proxy, return the readonly version.
if (!isReadonly(target)) {
{
if (isArray(target)) {
warn(`Avoid using Array as root value for ${shallow ? `shallowReactive()` : `reactive()`} as it cannot be tracked in watch() or watchEffect(). Use ${shallow ? `shallowRef()` : `ref()`} instead. This is a Vue-2-only limitation.`);
}
const existingOb = target && target.__ob__;
if (existingOb && existingOb.shallow !== shallow) {
warn(`Target is already a ${existingOb.shallow ? `` : `non-`}shallow reactive object, and cannot be converted to ${shallow ? `` : `non-`}shallow.`);
}
}
const ob = observe(target, shallow, isServerRendering() /* ssr mock reactivity */);
if (!ob) {
if (target == null || isPrimitive(target)) {
warn(`value cannot be made reactive: ${String(target)}`);
}
if (isCollectionType(target)) {
warn(`Vue 2 does not support reactive collection types such as Map or Set.`);
}
}
}
}
function isReactive(value) {
if (isReadonly(value)) {
return isReactive(value["__v_raw" /* ReactiveFlags.RAW */]);
}
return !!(value && value.__ob__);
}
function isShallow(value) {
return !!(value && value.__v_isShallow);
}
function isReadonly(value) {
return !!(value && value.__v_isReadonly);
}
function isProxy(value) {
return isReactive(value) || isReadonly(value);
}
function toRaw(observed) {
const raw = observed && observed["__v_raw" /* ReactiveFlags.RAW */];
return raw ? toRaw(raw) : observed;
}
function markRaw(value) {
// non-extensible objects won't be observed anyway
if (Object.isExtensible(value)) {
def(value, "__v_skip" /* ReactiveFlags.SKIP */, true);
}
return value;
}
/**
* @internal
*/
function isCollectionType(value) {
const type = toRawType(value);
return (type === 'Map' || type === 'WeakMap' || type === 'Set' || type === 'WeakSet');
}
/**
* @internal
*/
const RefFlag = `__v_isRef`;
function isRef(r) {
return !!(r && r.__v_isRef === true);
}
function ref$1(value) {
return createRef(value, false);
}
function shallowRef(value) {
return createRef(value, true);
}
function createRef(rawValue, shallow) {
if (isRef(rawValue)) {
return rawValue;
}
const ref = {};
def(ref, RefFlag, true);
def(ref, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, shallow);
def(ref, 'dep', defineReactive(ref, 'value', rawValue, null, shallow, isServerRendering()));
return ref;
}
function triggerRef(ref) {
if (!ref.dep) {
warn(`received object is not a triggerable ref.`);
}
{
ref.dep &&
ref.dep.notify({
type: "set" /* TriggerOpTypes.SET */,
target: ref,
key: 'value'
});
}
}
function unref(ref) {
return isRef(ref) ? ref.value : ref;
}
function proxyRefs(objectWithRefs) {
if (isReactive(objectWithRefs)) {
return objectWithRefs;
}
const proxy = {};
const keys = Object.keys(objectWithRefs);
for (let i = 0; i < keys.length; i++) {
proxyWithRefUnwrap(proxy, objectWithRefs, keys[i]);
}
return proxy;
}
function proxyWithRefUnwrap(target, source, key) {
Object.defineProperty(target, key, {
enumerable: true,
configurable: true,
get: () => {
const val = source[key];
if (isRef(val)) {
return val.value;
}
else {
const ob = val && val.__ob__;
if (ob)
ob.dep.depend();
return val;
}
},
set: value => {
const oldValue = source[key];
if (isRef(oldValue) && !isRef(value)) {
oldValue.value = value;
}
else {
source[key] = value;
}
}
});
}
function customRef(factory) {
const dep = new Dep();
const { get, set } = factory(() => {
{
dep.depend({
target: ref,
type: "get" /* TrackOpTypes.GET */,
key: 'value'
});
}
}, () => {
{
dep.notify({
target: ref,
type: "set" /* TriggerOpTypes.SET */,
key: 'value'
});
}
});
const ref = {
get value() {
return get();
},
set value(newVal) {
set(newVal);
}
};
def(ref, RefFlag, true);
return ref;
}
function toRefs(object) {
if (!isReactive(object)) {
warn(`toRefs() expects a reactive object but received a plain one.`);
}
const ret = isArray(object) ? new Array(object.length) : {};
for (const key in object) {
ret[key] = toRef(object, key);
}
return ret;
}
function toRef(object, key, defaultValue) {
const val = object[key];
if (isRef(val)) {
return val;
}
const ref = {
get value() {
const val = object[key];
return val === undefined ? defaultValue : val;
},
set value(newVal) {
object[key] = newVal;
}
};
def(ref, RefFlag, true);
return ref;
}
const rawToReadonlyFlag = `__v_rawToReadonly`;
const rawToShallowReadonlyFlag = `__v_rawToShallowReadonly`;
function readonly(target) {
return createReadonly(target, false);
}
function createReadonly(target, shallow) {
if (!isPlainObject(target)) {
{
if (isArray(target)) {
warn(`Vue 2 does not support readonly arrays.`);
}
else if (isCollectionType(target)) {
warn(`Vue 2 does not support readonly collection types such as Map or Set.`);
}
else {
warn(`value cannot be made readonly: ${typeof target}`);
}
}
return target;
}
if (!Object.isExtensible(target)) {
warn(`Vue 2 does not support creating readonly proxy for non-extensible object.`);
}
// already a readonly object
if (isReadonly(target)) {
return target;
}
// already has a readonly proxy
const existingFlag = shallow ? rawToShallowReadonlyFlag : rawToReadonlyFlag;
const existingProxy = target[existingFlag];
if (existingProxy) {
return existingProxy;
}
const proxy = Object.create(Object.getPrototypeOf(target));
def(target, existingFlag, proxy);
def(proxy, "__v_isReadonly" /* ReactiveFlags.IS_READONLY */, true);
def(proxy, "__v_raw" /* ReactiveFlags.RAW */, target);
if (isRef(target)) {
def(proxy, RefFlag, true);
}
if (shallow || isShallow(target)) {
def(proxy, "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */, true);
}
const keys = Object.keys(target);
for (let i = 0; i < keys.length; i++) {
defineReadonlyProperty(proxy, target, keys[i], shallow);
}
return proxy;
}
function defineReadonlyProperty(proxy, target, key, shallow) {
Object.defineProperty(proxy, key, {
enumerable: true,
configurable: true,
get() {
const val = target[key];
return shallow || !isPlainObject(val) ? val : readonly(val);
},
set() {
warn(`Set operation on key "${key}" failed: target is readonly.`);
}
});
}
/**
* Returns a reactive-copy of the original object, where only the root level
* properties are readonly, and does NOT unwrap refs nor recursively convert
* returned properties.
* This is used for creating the props proxy object for stateful components.
*/
function shallowReadonly(target) {
return createReadonly(target, true);
}
function computed(getterOrOptions, debugOptions) {
let getter;
let setter;
const onlyGetter = isFunction(getterOrOptions);
if (onlyGetter) {
getter = getterOrOptions;
setter = () => {
warn('Write operation failed: computed value is readonly');
}
;
}
else {
getter = getterOrOptions.get;
setter = getterOrOptions.set;
}
const watcher = isServerRendering()
? null
: new Watcher(currentInstance, getter, noop, { lazy: true });
if (watcher && debugOptions) {
watcher.onTrack = debugOptions.onTrack;
watcher.onTrigger = debugOptions.onTrigger;
}
const ref = {
// some libs rely on the presence effect for checking computed refs
// from normal refs, but the implementation doesn't matter
effect: watcher,
get value() {
if (watcher) {
if (watcher.dirty) {
watcher.evaluate();
}
if (Dep.target) {
if (Dep.target.onTrack) {
Dep.target.onTrack({
effect: Dep.target,
target: ref,
type: "get" /* TrackOpTypes.GET */,
key: 'value'
});
}
watcher.depend();
}
return watcher.value;
}
else {
return getter();
}
},
set value(newVal) {
setter(newVal);
}
};
def(ref, RefFlag, true);
def(ref, "__v_isReadonly" /* ReactiveFlags.IS_READONLY */, onlyGetter);
return ref;
}
const WATCHER = `watcher`;
const WATCHER_CB = `${WATCHER} callback`;
const WATCHER_GETTER = `${WATCHER} getter`;
const WATCHER_CLEANUP = `${WATCHER} cleanup`;
// Simple effect.
function watchEffect(effect, options) {
return doWatch(effect, null, options);
}
function watchPostEffect(effect, options) {
return doWatch(effect, null, (Object.assign(Object.assign({}, options), { flush: 'post' }) ));
}
function watchSyncEffect(effect, options) {
return doWatch(effect, null, (Object.assign(Object.assign({}, options), { flush: 'sync' }) ));
}
// initial value for watchers to trigger on undefined initial values
const INITIAL_WATCHER_VALUE = {};
// implementation
function watch(source, cb, options) {
if (typeof cb !== 'function') {
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 = 'pre', onTrack, onTrigger } = emptyObject) {
if (!cb) {
if (immediate !== undefined) {
warn(`watch() "immediate" option is only respected when using the ` +
`watch(source, callback, options?) signature.`);
}
if (deep !== undefined) {
warn(`watch() "deep" option is only respected when using the ` +
`watch(source, callback, options?) signature.`);
}
}
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.`);
};
const instance = currentInstance;
const call = (fn, type, args = null) => invokeWithErrorHandling(fn, null, args, instance, type);
let getter;
let forceTrigger = false;
let isMultiSource = false;
if (isRef(source)) {
getter = () => source.value;
forceTrigger = isShallow(source);
}
else if (isReactive(source)) {
getter = () => {
source.__ob__.dep.depend();
return source;
};
deep = true;
}
else if (isArray(source)) {
isMultiSource = true;
forceTrigger = source.some(s => isReactive(s) || isShallow(s));
getter = () => source.map(s => {
if (isRef(s)) {
return s.value;
}
else if (isReactive(s)) {
return traverse(s);
}
else if (isFunction(s)) {
return call(s, WATCHER_GETTER);
}
else {
warnInvalidSource(s);
}
});
}
else if (isFunction(source)) {
if (cb) {
// getter with cb
getter = () => call(source, WATCHER_GETTER);
}
else {
// no cb -> simple effect
getter = () => {
if (instance && instance._isDestroyed) {
return;
}
if (cleanup) {
cleanup();
}
return call(source, WATCHER, [onCleanup]);
};
}
}
else {
getter = noop;
warnInvalidSource(source);
}
if (cb && deep) {
const baseGetter = getter;
getter = () => traverse(baseGetter());
}
let cleanup;
let onCleanup = (fn) => {
cleanup = watcher.onStop = () => {
call(fn, WATCHER_CLEANUP);
};
};
// in SSR there is no need to setup an actual effect, and it should be noop
// unless it's eager
if (isServerRendering()) {
// we will also not call the invalidate callback (+ runner is not set up)
onCleanup = noop;
if (!cb) {
getter();
}
else if (immediate) {
call(cb, WATCHER_CB, [
getter(),
isMultiSource ? [] : undefined,
onCleanup
]);
}
return noop;
}
const watcher = new Watcher(currentInstance, getter, noop, {
lazy: true
});
watcher.noRecurse = !cb;
let oldValue = isMultiSource ? [] : INITIAL_WATCHER_VALUE;
// overwrite default run
watcher.run = () => {
if (!watcher.active) {
return;
}
if (cb) {
// watch(source, cb)
const newValue = watcher.get();
if (deep ||
forceTrigger ||
(isMultiSource
? newValue.some((v, i) => hasChanged(v, oldValue[i]))
: hasChanged(newValue, oldValue))) {
// cleanup before running cb again
if (cleanup) {
cleanup();
}
call(cb, WATCHER_CB, [
newValue,
// pass undefined as the old value when it's changed for the first time
oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue,
onCleanup
]);
oldValue = newValue;
}
}
else {
// watchEffect
watcher.get();
}
};
if (flush === 'sync') {
watcher.update = watcher.run;
}
else if (flush === 'post') {
watcher.post = true;
watcher.update = () => queueWatcher(watcher);
}
else {
// pre
watcher.update = () => {
if (instance && instance === currentInstance && !instance._isMounted) {
// pre-watcher triggered before
const buffer = instance._preWatchers || (instance._preWatchers = []);
if (buffer.indexOf(watcher) < 0)
buffer.push(watcher);
}
else {
queueWatcher(watcher);
}
};
}
{
watcher.onTrack = onTrack;
watcher.onTrigger = onTrigger;
}
// initial run
if (cb) {
if (immediate) {
watcher.run();
}
else {
oldValue = watcher.get();
}
}
else if (flush === 'post' && instance) {
instance.$once('hook:mounted', () => watcher.get());
}
else {
watcher.get();
}
return () => {
watcher.teardown();
};
}
let activeEffectScope;
class EffectScope {
constructor(detached = false) {
this.detached = detached;
/**
* @internal
*/
this.active = true;
/**
* @internal
*/
this.effects = [];
/**
* @internal
*/
this.cleanups = [];
this.parent = activeEffectScope;
if (!detached && activeEffectScope) {
this.index =
(activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(this) - 1;
}
}
run(fn) {
if (this.active) {
const currentEffectScope = activeEffectScope;
try {
activeEffectScope = this;
return fn();
}
finally {
activeEffectScope = currentEffectScope;
}
}
else {
warn(`cannot run an inactive effect scope.`);
}
}
/**
* This should only be called on non-detached scopes
* @internal
*/
on() {
activeEffectScope = this;
}
/**
* This should only be called on non-detached scopes
* @internal
*/
off() {
activeEffectScope = this.parent;
}
stop(fromParent) {
if (this.active) {
let i, l;
for (i = 0, l = this.effects.length; i < l; i++) {
this.effects[i].teardown();
}
for (i = 0, l = this.cleanups.length; i < l; i++) {
this.cleanups[i]();
}
if (this.scopes) {
for (i = 0, l = this.scopes.length; i < l; i++) {
this.scopes[i].stop(true);
}
}
// nested scope, dereference from parent to avoid memory leaks
if (!this.detached && this.parent && !fromParent) {
// optimized O(1) removal
const last = this.parent.scopes.pop();
if (last && last !== this) {
this.parent.scopes[this.index] = last;
last.index = this.index;
}
}
this.parent = undefined;
this.active = false;
}
}
}
function effectScope(detached) {
return new EffectScope(detached);
}
/**
* @internal
*/
function recordEffectScope(effect, scope = activeEffectScope) {
if (scope && scope.active) {
scope.effects.push(effect);
}
}
function getCurrentScope() {
return activeEffectScope;
}
function onScopeDispose(fn) {
if (activeEffectScope) {
activeEffectScope.cleanups.push(fn);
}
else {
warn(`onScopeDispose() is called when there is no active effect scope` +
` to be associated with.`);
}
}
function provide(key, value) {
if (!currentInstance) {
{
warn(`provide() can only be used inside setup().`);
}
}
else {
// TS doesn't allow symbol as index type
resolveProvided(currentInstance)[key] = value;
}
}
function resolveProvided(vm) {
// by default an instance inherits its parent's provides object
// but when it needs to provide values of its own, it creates its
// own provides object using parent provides object as prototype.
// this way in `inject` we can simply look up injections from direct
// parent and let the prototype chain do the work.
const existing = vm._provided;
const parentProvides = vm.$parent && vm.$parent._provided;
if (parentProvides === existing) {
return (vm._provided = Object.create(parentProvides));
}
else {
return existing;
}
}
function inject(key, defaultValue, treatDefaultAsFactory = false) {
// fallback to `currentRenderingInstance` so that this can be called in
// a functional component
const instance = currentInstance;
if (instance) {
// #2400
// to support `app.use` plugins,
// fallback to appContext's `provides` if the instance is at root
const provides = instance.$parent && instance.$parent._provided;
if (provides && key in provides) {
// TS doesn't allow symbol as index type
return provides[key];
}
else if (arguments.length > 1) {
return treatDefaultAsFactory && isFunction(defaultValue)
? defaultValue.call(instance)
: defaultValue;
}
else {
warn(`injection "${String(key)}" not found.`);
}
}
else {
warn(`inject() can only be used inside setup() or functional components.`);
}
}
const normalizeEvent = cached((name) => {
const passive = name.charAt(0) === '&';
name = passive ? name.slice(1) : name;
const once = name.charAt(0) === '~'; // Prefixed last, checked first
name = once ? name.slice(1)