You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1252 lines
41 KiB
1252 lines
41 KiB
2 years ago
|
import { extend, isArray, isMap, isIntegerKey, hasOwn, isSymbol, isObject, hasChanged, makeMap, capitalize, toRawType, def, isFunction, NOOP } from '@vue/shared';
|
||
|
|
||
|
function warn(msg, ...args) {
|
||
|
console.warn(`[Vue warn] ${msg}`, ...args);
|
||
|
}
|
||
|
|
||
|
let activeEffectScope;
|
||
|
class EffectScope {
|
||
|
constructor(detached = false) {
|
||
|
/**
|
||
|
* @internal
|
||
|
*/
|
||
|
this.active = true;
|
||
|
/**
|
||
|
* @internal
|
||
|
*/
|
||
|
this.effects = [];
|
||
|
/**
|
||
|
* @internal
|
||
|
*/
|
||
|
this.cleanups = [];
|
||
|
if (!detached && activeEffectScope) {
|
||
|
this.parent = 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 if ((process.env.NODE_ENV !== 'production')) {
|
||
|
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].stop();
|
||
|
}
|
||
|
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.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.active = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function effectScope(detached) {
|
||
|
return new EffectScope(detached);
|
||
|
}
|
||
|
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 if ((process.env.NODE_ENV !== 'production')) {
|
||
|
warn(`onScopeDispose() is called when there is no active effect scope` +
|
||
|
` to be associated with.`);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const createDep = (effects) => {
|
||
|
const dep = new Set(effects);
|
||
|
dep.w = 0;
|
||
|
dep.n = 0;
|
||
|
return dep;
|
||
|
};
|
||
|
const wasTracked = (dep) => (dep.w & trackOpBit) > 0;
|
||
|
const newTracked = (dep) => (dep.n & trackOpBit) > 0;
|
||
|
const initDepMarkers = ({ deps }) => {
|
||
|
if (deps.length) {
|
||
|
for (let i = 0; i < deps.length; i++) {
|
||
|
deps[i].w |= trackOpBit; // set was tracked
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
const finalizeDepMarkers = (effect) => {
|
||
|
const { deps } = effect;
|
||
|
if (deps.length) {
|
||
|
let ptr = 0;
|
||
|
for (let i = 0; i < deps.length; i++) {
|
||
|
const dep = deps[i];
|
||
|
if (wasTracked(dep) && !newTracked(dep)) {
|
||
|
dep.delete(effect);
|
||
|
}
|
||
|
else {
|
||
|
deps[ptr++] = dep;
|
||
|
}
|
||
|
// clear bits
|
||
|
dep.w &= ~trackOpBit;
|
||
|
dep.n &= ~trackOpBit;
|
||
|
}
|
||
|
deps.length = ptr;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const targetMap = new WeakMap();
|
||
|
// The number of effects currently being tracked recursively.
|
||
|
let effectTrackDepth = 0;
|
||
|
let trackOpBit = 1;
|
||
|
/**
|
||
|
* The bitwise track markers support at most 30 levels of recursion.
|
||
|
* This value is chosen to enable modern JS engines to use a SMI on all platforms.
|
||
|
* When recursion depth is greater, fall back to using a full cleanup.
|
||
|
*/
|
||
|
const maxMarkerBits = 30;
|
||
|
let activeEffect;
|
||
|
const ITERATE_KEY = Symbol((process.env.NODE_ENV !== 'production') ? 'iterate' : '');
|
||
|
const MAP_KEY_ITERATE_KEY = Symbol((process.env.NODE_ENV !== 'production') ? 'Map key iterate' : '');
|
||
|
class ReactiveEffect {
|
||
|
constructor(fn, scheduler = null, scope) {
|
||
|
this.fn = fn;
|
||
|
this.scheduler = scheduler;
|
||
|
this.active = true;
|
||
|
this.deps = [];
|
||
|
this.parent = undefined;
|
||
|
recordEffectScope(this, scope);
|
||
|
}
|
||
|
run() {
|
||
|
if (!this.active) {
|
||
|
return this.fn();
|
||
|
}
|
||
|
let parent = activeEffect;
|
||
|
let lastShouldTrack = shouldTrack;
|
||
|
while (parent) {
|
||
|
if (parent === this) {
|
||
|
return;
|
||
|
}
|
||
|
parent = parent.parent;
|
||
|
}
|
||
|
try {
|
||
|
this.parent = activeEffect;
|
||
|
activeEffect = this;
|
||
|
shouldTrack = true;
|
||
|
trackOpBit = 1 << ++effectTrackDepth;
|
||
|
if (effectTrackDepth <= maxMarkerBits) {
|
||
|
initDepMarkers(this);
|
||
|
}
|
||
|
else {
|
||
|
cleanupEffect(this);
|
||
|
}
|
||
|
return this.fn();
|
||
|
}
|
||
|
finally {
|
||
|
if (effectTrackDepth <= maxMarkerBits) {
|
||
|
finalizeDepMarkers(this);
|
||
|
}
|
||
|
trackOpBit = 1 << --effectTrackDepth;
|
||
|
activeEffect = this.parent;
|
||
|
shouldTrack = lastShouldTrack;
|
||
|
this.parent = undefined;
|
||
|
if (this.deferStop) {
|
||
|
this.stop();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
stop() {
|
||
|
// stopped while running itself - defer the cleanup
|
||
|
if (activeEffect === this) {
|
||
|
this.deferStop = true;
|
||
|
}
|
||
|
else if (this.active) {
|
||
|
cleanupEffect(this);
|
||
|
if (this.onStop) {
|
||
|
this.onStop();
|
||
|
}
|
||
|
this.active = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function cleanupEffect(effect) {
|
||
|
const { deps } = effect;
|
||
|
if (deps.length) {
|
||
|
for (let i = 0; i < deps.length; i++) {
|
||
|
deps[i].delete(effect);
|
||
|
}
|
||
|
deps.length = 0;
|
||
|
}
|
||
|
}
|
||
|
function effect(fn, options) {
|
||
|
if (fn.effect) {
|
||
|
fn = fn.effect.fn;
|
||
|
}
|
||
|
const _effect = new ReactiveEffect(fn);
|
||
|
if (options) {
|
||
|
extend(_effect, options);
|
||
|
if (options.scope)
|
||
|
recordEffectScope(_effect, options.scope);
|
||
|
}
|
||
|
if (!options || !options.lazy) {
|
||
|
_effect.run();
|
||
|
}
|
||
|
const runner = _effect.run.bind(_effect);
|
||
|
runner.effect = _effect;
|
||
|
return runner;
|
||
|
}
|
||
|
function stop(runner) {
|
||
|
runner.effect.stop();
|
||
|
}
|
||
|
let shouldTrack = true;
|
||
|
const trackStack = [];
|
||
|
function pauseTracking() {
|
||
|
trackStack.push(shouldTrack);
|
||
|
shouldTrack = false;
|
||
|
}
|
||
|
function enableTracking() {
|
||
|
trackStack.push(shouldTrack);
|
||
|
shouldTrack = true;
|
||
|
}
|
||
|
function resetTracking() {
|
||
|
const last = trackStack.pop();
|
||
|
shouldTrack = last === undefined ? true : last;
|
||
|
}
|
||
|
function track(target, type, key) {
|
||
|
if (shouldTrack && activeEffect) {
|
||
|
let depsMap = targetMap.get(target);
|
||
|
if (!depsMap) {
|
||
|
targetMap.set(target, (depsMap = new Map()));
|
||
|
}
|
||
|
let dep = depsMap.get(key);
|
||
|
if (!dep) {
|
||
|
depsMap.set(key, (dep = createDep()));
|
||
|
}
|
||
|
const eventInfo = (process.env.NODE_ENV !== 'production')
|
||
|
? { effect: activeEffect, target, type, key }
|
||
|
: undefined;
|
||
|
trackEffects(dep, eventInfo);
|
||
|
}
|
||
|
}
|
||
|
function trackEffects(dep, debuggerEventExtraInfo) {
|
||
|
let shouldTrack = false;
|
||
|
if (effectTrackDepth <= maxMarkerBits) {
|
||
|
if (!newTracked(dep)) {
|
||
|
dep.n |= trackOpBit; // set newly tracked
|
||
|
shouldTrack = !wasTracked(dep);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// Full cleanup mode.
|
||
|
shouldTrack = !dep.has(activeEffect);
|
||
|
}
|
||
|
if (shouldTrack) {
|
||
|
dep.add(activeEffect);
|
||
|
activeEffect.deps.push(dep);
|
||
|
if ((process.env.NODE_ENV !== 'production') && activeEffect.onTrack) {
|
||
|
activeEffect.onTrack(Object.assign({ effect: activeEffect }, debuggerEventExtraInfo));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function trigger(target, type, key, newValue, oldValue, oldTarget) {
|
||
|
const depsMap = targetMap.get(target);
|
||
|
if (!depsMap) {
|
||
|
// never been tracked
|
||
|
return;
|
||
|
}
|
||
|
let deps = [];
|
||
|
if (type === "clear" /* CLEAR */) {
|
||
|
// collection being cleared
|
||
|
// trigger all effects for target
|
||
|
deps = [...depsMap.values()];
|
||
|
}
|
||
|
else if (key === 'length' && isArray(target)) {
|
||
|
depsMap.forEach((dep, key) => {
|
||
|
if (key === 'length' || key >= newValue) {
|
||
|
deps.push(dep);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
// schedule runs for SET | ADD | DELETE
|
||
|
if (key !== void 0) {
|
||
|
deps.push(depsMap.get(key));
|
||
|
}
|
||
|
// also run for iteration key on ADD | DELETE | Map.SET
|
||
|
switch (type) {
|
||
|
case "add" /* ADD */:
|
||
|
if (!isArray(target)) {
|
||
|
deps.push(depsMap.get(ITERATE_KEY));
|
||
|
if (isMap(target)) {
|
||
|
deps.push(depsMap.get(MAP_KEY_ITERATE_KEY));
|
||
|
}
|
||
|
}
|
||
|
else if (isIntegerKey(key)) {
|
||
|
// new index added to array -> length changes
|
||
|
deps.push(depsMap.get('length'));
|
||
|
}
|
||
|
break;
|
||
|
case "delete" /* DELETE */:
|
||
|
if (!isArray(target)) {
|
||
|
deps.push(depsMap.get(ITERATE_KEY));
|
||
|
if (isMap(target)) {
|
||
|
deps.push(depsMap.get(MAP_KEY_ITERATE_KEY));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case "set" /* SET */:
|
||
|
if (isMap(target)) {
|
||
|
deps.push(depsMap.get(ITERATE_KEY));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
const eventInfo = (process.env.NODE_ENV !== 'production')
|
||
|
? { target, type, key, newValue, oldValue, oldTarget }
|
||
|
: undefined;
|
||
|
if (deps.length === 1) {
|
||
|
if (deps[0]) {
|
||
|
if ((process.env.NODE_ENV !== 'production')) {
|
||
|
triggerEffects(deps[0], eventInfo);
|
||
|
}
|
||
|
else {
|
||
|
triggerEffects(deps[0]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
const effects = [];
|
||
|
for (const dep of deps) {
|
||
|
if (dep) {
|
||
|
effects.push(...dep);
|
||
|
}
|
||
|
}
|
||
|
if ((process.env.NODE_ENV !== 'production')) {
|
||
|
triggerEffects(createDep(effects), eventInfo);
|
||
|
}
|
||
|
else {
|
||
|
triggerEffects(createDep(effects));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function triggerEffects(dep, debuggerEventExtraInfo) {
|
||
|
// spread into array for stabilization
|
||
|
const effects = isArray(dep) ? dep : [...dep];
|
||
|
for (const effect of effects) {
|
||
|
if (effect.computed) {
|
||
|
triggerEffect(effect, debuggerEventExtraInfo);
|
||
|
}
|
||
|
}
|
||
|
for (const effect of effects) {
|
||
|
if (!effect.computed) {
|
||
|
triggerEffect(effect, debuggerEventExtraInfo);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function triggerEffect(effect, debuggerEventExtraInfo) {
|
||
|
if (effect !== activeEffect || effect.allowRecurse) {
|
||
|
if ((process.env.NODE_ENV !== 'production') && effect.onTrigger) {
|
||
|
effect.onTrigger(extend({ effect }, debuggerEventExtraInfo));
|
||
|
}
|
||
|
if (effect.scheduler) {
|
||
|
effect.scheduler();
|
||
|
}
|
||
|
else {
|
||
|
effect.run();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const isNonTrackableKeys = /*#__PURE__*/ makeMap(`__proto__,__v_isRef,__isVue`);
|
||
|
const builtInSymbols = new Set(
|
||
|
/*#__PURE__*/
|
||
|
Object.getOwnPropertyNames(Symbol)
|
||
|
// ios10.x Object.getOwnPropertyNames(Symbol) can enumerate 'arguments' and 'caller'
|
||
|
// but accessing them on Symbol leads to TypeError because Symbol is a strict mode
|
||
|
// function
|
||
|
.filter(key => key !== 'arguments' && key !== 'caller')
|
||
|
.map(key => Symbol[key])
|
||
|
.filter(isSymbol));
|
||
|
const get = /*#__PURE__*/ createGetter();
|
||
|
const shallowGet = /*#__PURE__*/ createGetter(false, true);
|
||
|
const readonlyGet = /*#__PURE__*/ createGetter(true);
|
||
|
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true);
|
||
|
const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations();
|
||
|
function createArrayInstrumentations() {
|
||
|
const instrumentations = {};
|
||
|
['includes', 'indexOf', 'lastIndexOf'].forEach(key => {
|
||
|
instrumentations[key] = function (...args) {
|
||
|
const arr = toRaw(this);
|
||
|
for (let i = 0, l = this.length; i < l; i++) {
|
||
|
track(arr, "get" /* GET */, i + '');
|
||
|
}
|
||
|
// we run the method using the original args first (which may be reactive)
|
||
|
const res = arr[key](...args);
|
||
|
if (res === -1 || res === false) {
|
||
|
// if that didn't work, run it again using raw values.
|
||
|
return arr[key](...args.map(toRaw));
|
||
|
}
|
||
|
else {
|
||
|
return res;
|
||
|
}
|
||
|
};
|
||
|
});
|
||
|
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => {
|
||
|
instrumentations[key] = function (...args) {
|
||
|
pauseTracking();
|
||
|
const res = toRaw(this)[key].apply(this, args);
|
||
|
resetTracking();
|
||
|
return res;
|
||
|
};
|
||
|
});
|
||
|
return instrumentations;
|
||
|
}
|
||
|
function createGetter(isReadonly = false, shallow = false) {
|
||
|
return function get(target, key, receiver) {
|
||
|
if (key === "__v_isReactive" /* IS_REACTIVE */) {
|
||
|
return !isReadonly;
|
||
|
}
|
||
|
else if (key === "__v_isReadonly" /* IS_READONLY */) {
|
||
|
return isReadonly;
|
||
|
}
|
||
|
else if (key === "__v_isShallow" /* IS_SHALLOW */) {
|
||
|
return shallow;
|
||
|
}
|
||
|
else if (key === "__v_raw" /* RAW */ &&
|
||
|
receiver ===
|
||
|
(isReadonly
|
||
|
? shallow
|
||
|
? shallowReadonlyMap
|
||
|
: readonlyMap
|
||
|
: shallow
|
||
|
? shallowReactiveMap
|
||
|
: reactiveMap).get(target)) {
|
||
|
return target;
|
||
|
}
|
||
|
const targetIsArray = isArray(target);
|
||
|
if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
|
||
|
return Reflect.get(arrayInstrumentations, key, receiver);
|
||
|
}
|
||
|
const res = Reflect.get(target, key, receiver);
|
||
|
if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
|
||
|
return res;
|
||
|
}
|
||
|
if (!isReadonly) {
|
||
|
track(target, "get" /* GET */, key);
|
||
|
}
|
||
|
if (shallow) {
|
||
|
return res;
|
||
|
}
|
||
|
if (isRef(res)) {
|
||
|
// ref unwrapping - skip unwrap for Array + integer key.
|
||
|
return targetIsArray && isIntegerKey(key) ? res : res.value;
|
||
|
}
|
||
|
if (isObject(res)) {
|
||
|
// Convert returned value into a proxy as well. we do the isObject check
|
||
|
// here to avoid invalid value warning. Also need to lazy access readonly
|
||
|
// and reactive here to avoid circular dependency.
|
||
|
return isReadonly ? readonly(res) : reactive(res);
|
||
|
}
|
||
|
return res;
|
||
|
};
|
||
|
}
|
||
|
const set = /*#__PURE__*/ createSetter();
|
||
|
const shallowSet = /*#__PURE__*/ createSetter(true);
|
||
|
function createSetter(shallow = false) {
|
||
|
return function set(target, key, value, receiver) {
|
||
|
let oldValue = target[key];
|
||
|
if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
|
||
|
return false;
|
||
|
}
|
||
|
if (!shallow && !isReadonly(value)) {
|
||
|
if (!isShallow(value)) {
|
||
|
value = toRaw(value);
|
||
|
oldValue = toRaw(oldValue);
|
||
|
}
|
||
|
if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
|
||
|
oldValue.value = value;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
const hadKey = isArray(target) && isIntegerKey(key)
|
||
|
? Number(key) < target.length
|
||
|
: 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)) {
|
||
|
if (!hadKey) {
|
||
|
trigger(target, "add" /* ADD */, key, value);
|
||
|
}
|
||
|
else if (hasChanged(value, oldValue)) {
|
||
|
trigger(target, "set" /* SET */, key, value, oldValue);
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
};
|
||
|
}
|
||
|
function deleteProperty(target, key) {
|
||
|
const hadKey = hasOwn(target, key);
|
||
|
const oldValue = target[key];
|
||
|
const result = Reflect.deleteProperty(target, key);
|
||
|
if (result && hadKey) {
|
||
|
trigger(target, "delete" /* DELETE */, key, undefined, oldValue);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
function has(target, key) {
|
||
|
const result = Reflect.has(target, key);
|
||
|
if (!isSymbol(key) || !builtInSymbols.has(key)) {
|
||
|
track(target, "has" /* HAS */, key);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
function ownKeys(target) {
|
||
|
track(target, "iterate" /* ITERATE */, isArray(target) ? 'length' : ITERATE_KEY);
|
||
|
return Reflect.ownKeys(target);
|
||
|
}
|
||
|
const mutableHandlers = {
|
||
|
get,
|
||
|
set,
|
||
|
deleteProperty,
|
||
|
has,
|
||
|
ownKeys
|
||
|
};
|
||
|
const readonlyHandlers = {
|
||
|
get: readonlyGet,
|
||
|
set(target, key) {
|
||
|
if ((process.env.NODE_ENV !== 'production')) {
|
||
|
warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target);
|
||
|
}
|
||
|
return true;
|
||
|
},
|
||
|
deleteProperty(target, key) {
|
||
|
if ((process.env.NODE_ENV !== 'production')) {
|
||
|
warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
const shallowReactiveHandlers = /*#__PURE__*/ extend({}, mutableHandlers, {
|
||
|
get: shallowGet,
|
||
|
set: shallowSet
|
||
|
});
|
||
|
// Props handlers are special in the sense that it should not unwrap top-level
|
||
|
// refs (in order to allow refs to be explicitly passed down), but should
|
||
|
// retain the reactivity of the normal readonly object.
|
||
|
const shallowReadonlyHandlers = /*#__PURE__*/ extend({}, readonlyHandlers, {
|
||
|
get: shallowReadonlyGet
|
||
|
});
|
||
|
|
||
|
const toShallow = (value) => value;
|
||
|
const getProto = (v) => Reflect.getPrototypeOf(v);
|
||
|
function get$1(target, key, isReadonly = false, isShallow = false) {
|
||
|
// #1772: readonly(reactive(Map)) should return readonly + reactive version
|
||
|
// of the value
|
||
|
target = target["__v_raw" /* RAW */];
|
||
|
const rawTarget = toRaw(target);
|
||
|
const rawKey = toRaw(key);
|
||
|
if (!isReadonly) {
|
||
|
if (key !== rawKey) {
|
||
|
track(rawTarget, "get" /* GET */, key);
|
||
|
}
|
||
|
track(rawTarget, "get" /* GET */, rawKey);
|
||
|
}
|
||
|
const { has } = getProto(rawTarget);
|
||
|
const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
|
||
|
if (has.call(rawTarget, key)) {
|
||
|
return wrap(target.get(key));
|
||
|
}
|
||
|
else if (has.call(rawTarget, rawKey)) {
|
||
|
return wrap(target.get(rawKey));
|
||
|
}
|
||
|
else if (target !== rawTarget) {
|
||
|
// #3602 readonly(reactive(Map))
|
||
|
// ensure that the nested reactive `Map` can do tracking for itself
|
||
|
target.get(key);
|
||
|
}
|
||
|
}
|
||
|
function has$1(key, isReadonly = false) {
|
||
|
const target = this["__v_raw" /* RAW */];
|
||
|
const rawTarget = toRaw(target);
|
||
|
const rawKey = toRaw(key);
|
||
|
if (!isReadonly) {
|
||
|
if (key !== rawKey) {
|
||
|
track(rawTarget, "has" /* HAS */, key);
|
||
|
}
|
||
|
track(rawTarget, "has" /* HAS */, rawKey);
|
||
|
}
|
||
|
return key === rawKey
|
||
|
? target.has(key)
|
||
|
: target.has(key) || target.has(rawKey);
|
||
|
}
|
||
|
function size(target, isReadonly = false) {
|
||
|
target = target["__v_raw" /* RAW */];
|
||
|
!isReadonly && track(toRaw(target), "iterate" /* ITERATE */, ITERATE_KEY);
|
||
|
return Reflect.get(target, 'size', target);
|
||
|
}
|
||
|
function add(value) {
|
||
|
value = toRaw(value);
|
||
|
const target = toRaw(this);
|
||
|
const proto = getProto(target);
|
||
|
const hadKey = proto.has.call(target, value);
|
||
|
if (!hadKey) {
|
||
|
target.add(value);
|
||
|
trigger(target, "add" /* ADD */, value, value);
|
||
|
}
|
||
|
return this;
|
||
|
}
|
||
|
function set$1(key, value) {
|
||
|
value = toRaw(value);
|
||
|
const target = toRaw(this);
|
||
|
const { has, get } = getProto(target);
|
||
|
let hadKey = has.call(target, key);
|
||
|
if (!hadKey) {
|
||
|
key = toRaw(key);
|
||
|
hadKey = has.call(target, key);
|
||
|
}
|
||
|
else if ((process.env.NODE_ENV !== 'production')) {
|
||
|
checkIdentityKeys(target, has, key);
|
||
|
}
|
||
|
const oldValue = get.call(target, key);
|
||
|
target.set(key, value);
|
||
|
if (!hadKey) {
|
||
|
trigger(target, "add" /* ADD */, key, value);
|
||
|
}
|
||
|
else if (hasChanged(value, oldValue)) {
|
||
|
trigger(target, "set" /* SET */, key, value, oldValue);
|
||
|
}
|
||
|
return this;
|
||
|
}
|
||
|
function deleteEntry(key) {
|
||
|
const target = toRaw(this);
|
||
|
const { has, get } = getProto(target);
|
||
|
let hadKey = has.call(target, key);
|
||
|
if (!hadKey) {
|
||
|
key = toRaw(key);
|
||
|
hadKey = has.call(target, key);
|
||
|
}
|
||
|
else if ((process.env.NODE_ENV !== 'production')) {
|
||
|
checkIdentityKeys(target, has, key);
|
||
|
}
|
||
|
const oldValue = get ? get.call(target, key) : undefined;
|
||
|
// forward the operation before queueing reactions
|
||
|
const result = target.delete(key);
|
||
|
if (hadKey) {
|
||
|
trigger(target, "delete" /* DELETE */, key, undefined, oldValue);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
function clear() {
|
||
|
const target = toRaw(this);
|
||
|
const hadItems = target.size !== 0;
|
||
|
const oldTarget = (process.env.NODE_ENV !== 'production')
|
||
|
? isMap(target)
|
||
|
? new Map(target)
|
||
|
: new Set(target)
|
||
|
: undefined;
|
||
|
// forward the operation before queueing reactions
|
||
|
const result = target.clear();
|
||
|
if (hadItems) {
|
||
|
trigger(target, "clear" /* CLEAR */, undefined, undefined, oldTarget);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
function createForEach(isReadonly, isShallow) {
|
||
|
return function forEach(callback, thisArg) {
|
||
|
const observed = this;
|
||
|
const target = observed["__v_raw" /* RAW */];
|
||
|
const rawTarget = toRaw(target);
|
||
|
const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
|
||
|
!isReadonly && track(rawTarget, "iterate" /* ITERATE */, ITERATE_KEY);
|
||
|
return target.forEach((value, key) => {
|
||
|
// important: make 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.
|
||
|
return callback.call(thisArg, wrap(value), wrap(key), observed);
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
function createIterableMethod(method, isReadonly, isShallow) {
|
||
|
return function (...args) {
|
||
|
const target = this["__v_raw" /* RAW */];
|
||
|
const rawTarget = toRaw(target);
|
||
|
const targetIsMap = isMap(rawTarget);
|
||
|
const isPair = method === 'entries' || (method === Symbol.iterator && targetIsMap);
|
||
|
const isKeyOnly = method === 'keys' && targetIsMap;
|
||
|
const innerIterator = target[method](...args);
|
||
|
const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;
|
||
|
!isReadonly &&
|
||
|
track(rawTarget, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY);
|
||
|
// 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(type) {
|
||
|
return function (...args) {
|
||
|
if ((process.env.NODE_ENV !== 'production')) {
|
||
|
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;
|
||
|
};
|
||
|
}
|
||
|
function createInstrumentations() {
|
||
|
const mutableInstrumentations = {
|
||
|
get(key) {
|
||
|
return get$1(this, key);
|
||
|
},
|
||
|
get size() {
|
||
|
return size(this);
|
||
|
},
|
||
|
has: has$1,
|
||
|
add,
|
||
|
set: set$1,
|
||
|
delete: deleteEntry,
|
||
|
clear,
|
||
|
forEach: createForEach(false, false)
|
||
|
};
|
||
|
const shallowInstrumentations = {
|
||
|
get(key) {
|
||
|
return get$1(this, key, false, true);
|
||
|
},
|
||
|
get size() {
|
||
|
return size(this);
|
||
|
},
|
||
|
has: has$1,
|
||
|
add,
|
||
|
set: set$1,
|
||
|
delete: deleteEntry,
|
||
|
clear,
|
||
|
forEach: createForEach(false, true)
|
||
|
};
|
||
|
const readonlyInstrumentations = {
|
||
|
get(key) {
|
||
|
return get$1(this, key, true);
|
||
|
},
|
||
|
get size() {
|
||
|
return size(this, true);
|
||
|
},
|
||
|
has(key) {
|
||
|
return has$1.call(this, key, true);
|
||
|
},
|
||
|
add: createReadonlyMethod("add" /* ADD */),
|
||
|
set: createReadonlyMethod("set" /* SET */),
|
||
|
delete: createReadonlyMethod("delete" /* DELETE */),
|
||
|
clear: createReadonlyMethod("clear" /* CLEAR */),
|
||
|
forEach: createForEach(true, false)
|
||
|
};
|
||
|
const shallowReadonlyInstrumentations = {
|
||
|
get(key) {
|
||
|
return get$1(this, key, true, true);
|
||
|
},
|
||
|
get size() {
|
||
|
return size(this, true);
|
||
|
},
|
||
|
has(key) {
|
||
|
return has$1.call(this, key, true);
|
||
|
},
|
||
|
add: createReadonlyMethod("add" /* ADD */),
|
||
|
set: createReadonlyMethod("set" /* SET */),
|
||
|
delete: createReadonlyMethod("delete" /* DELETE */),
|
||
|
clear: createReadonlyMethod("clear" /* CLEAR */),
|
||
|
forEach: createForEach(true, true)
|
||
|
};
|
||
|
const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator];
|
||
|
iteratorMethods.forEach(method => {
|
||
|
mutableInstrumentations[method] = createIterableMethod(method, false, false);
|
||
|
readonlyInstrumentations[method] = createIterableMethod(method, true, false);
|
||
|
shallowInstrumentations[method] = createIterableMethod(method, false, true);
|
||
|
shallowReadonlyInstrumentations[method] = createIterableMethod(method, true, true);
|
||
|
});
|
||
|
return [
|
||
|
mutableInstrumentations,
|
||
|
readonlyInstrumentations,
|
||
|
shallowInstrumentations,
|
||
|
shallowReadonlyInstrumentations
|
||
|
];
|
||
|
}
|
||
|
const [mutableInstrumentations, readonlyInstrumentations, shallowInstrumentations, shallowReadonlyInstrumentations] = /* #__PURE__*/ createInstrumentations();
|
||
|
function createInstrumentationGetter(isReadonly, shallow) {
|
||
|
const instrumentations = shallow
|
||
|
? isReadonly
|
||
|
? shallowReadonlyInstrumentations
|
||
|
: shallowInstrumentations
|
||
|
: isReadonly
|
||
|
? readonlyInstrumentations
|
||
|
: mutableInstrumentations;
|
||
|
return (target, key, receiver) => {
|
||
|
if (key === "__v_isReactive" /* IS_REACTIVE */) {
|
||
|
return !isReadonly;
|
||
|
}
|
||
|
else if (key === "__v_isReadonly" /* IS_READONLY */) {
|
||
|
return isReadonly;
|
||
|
}
|
||
|
else if (key === "__v_raw" /* RAW */) {
|
||
|
return target;
|
||
|
}
|
||
|
return Reflect.get(hasOwn(instrumentations, key) && key in target
|
||
|
? instrumentations
|
||
|
: target, key, receiver);
|
||
|
};
|
||
|
}
|
||
|
const mutableCollectionHandlers = {
|
||
|
get: /*#__PURE__*/ createInstrumentationGetter(false, false)
|
||
|
};
|
||
|
const shallowCollectionHandlers = {
|
||
|
get: /*#__PURE__*/ createInstrumentationGetter(false, true)
|
||
|
};
|
||
|
const readonlyCollectionHandlers = {
|
||
|
get: /*#__PURE__*/ createInstrumentationGetter(true, false)
|
||
|
};
|
||
|
const shallowReadonlyCollectionHandlers = {
|
||
|
get: /*#__PURE__*/ createInstrumentationGetter(true, true)
|
||
|
};
|
||
|
function checkIdentityKeys(target, has, key) {
|
||
|
const rawKey = toRaw(key);
|
||
|
if (rawKey !== key && has.call(target, rawKey)) {
|
||
|
const type = toRawType(target);
|
||
|
console.warn(`Reactive ${type} contains both the raw and reactive ` +
|
||
|
`versions of the same object${type === `Map` ? ` as keys` : ``}, ` +
|
||
|
`which can lead to inconsistencies. ` +
|
||
|
`Avoid differentiating between the raw and reactive versions ` +
|
||
|
`of an object and only use the reactive version if possible.`);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const reactiveMap = new WeakMap();
|
||
|
const shallowReactiveMap = new WeakMap();
|
||
|
const readonlyMap = new WeakMap();
|
||
|
const shallowReadonlyMap = new WeakMap();
|
||
|
function targetTypeMap(rawType) {
|
||
|
switch (rawType) {
|
||
|
case 'Object':
|
||
|
case 'Array':
|
||
|
return 1 /* COMMON */;
|
||
|
case 'Map':
|
||
|
case 'Set':
|
||
|
case 'WeakMap':
|
||
|
case 'WeakSet':
|
||
|
return 2 /* COLLECTION */;
|
||
|
default:
|
||
|
return 0 /* INVALID */;
|
||
|
}
|
||
|
}
|
||
|
function getTargetType(value) {
|
||
|
return value["__v_skip" /* SKIP */] || !Object.isExtensible(value)
|
||
|
? 0 /* INVALID */
|
||
|
: targetTypeMap(toRawType(value));
|
||
|
}
|
||
|
function reactive(target) {
|
||
|
// if trying to observe a readonly proxy, return the readonly version.
|
||
|
if (isReadonly(target)) {
|
||
|
return target;
|
||
|
}
|
||
|
return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
|
||
|
}
|
||
|
/**
|
||
|
* 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) {
|
||
|
return createReactiveObject(target, false, shallowReactiveHandlers, shallowCollectionHandlers, shallowReactiveMap);
|
||
|
}
|
||
|
/**
|
||
|
* Creates a readonly copy of the original object. Note the returned copy is not
|
||
|
* made reactive, but `readonly` can be called on an already reactive object.
|
||
|
*/
|
||
|
function readonly(target) {
|
||
|
return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap);
|
||
|
}
|
||
|
/**
|
||
|
* 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 createReactiveObject(target, true, shallowReadonlyHandlers, shallowReadonlyCollectionHandlers, shallowReadonlyMap);
|
||
|
}
|
||
|
function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) {
|
||
|
if (!isObject(target)) {
|
||
|
if ((process.env.NODE_ENV !== 'production')) {
|
||
|
console.warn(`value cannot be made reactive: ${String(target)}`);
|
||
|
}
|
||
|
return target;
|
||
|
}
|
||
|
// target is already a Proxy, return it.
|
||
|
// exception: calling readonly() on a reactive object
|
||
|
if (target["__v_raw" /* RAW */] &&
|
||
|
!(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) {
|
||
|
return target;
|
||
|
}
|
||
|
// target already has corresponding Proxy
|
||
|
const existingProxy = proxyMap.get(target);
|
||
|
if (existingProxy) {
|
||
|
return existingProxy;
|
||
|
}
|
||
|
// only specific value types can be observed.
|
||
|
const targetType = getTargetType(target);
|
||
|
if (targetType === 0 /* INVALID */) {
|
||
|
return target;
|
||
|
}
|
||
|
const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers);
|
||
|
proxyMap.set(target, proxy);
|
||
|
return proxy;
|
||
|
}
|
||
|
function isReactive(value) {
|
||
|
if (isReadonly(value)) {
|
||
|
return isReactive(value["__v_raw" /* RAW */]);
|
||
|
}
|
||
|
return !!(value && value["__v_isReactive" /* IS_REACTIVE */]);
|
||
|
}
|
||
|
function isReadonly(value) {
|
||
|
return !!(value && value["__v_isReadonly" /* IS_READONLY */]);
|
||
|
}
|
||
|
function isShallow(value) {
|
||
|
return !!(value && value["__v_isShallow" /* IS_SHALLOW */]);
|
||
|
}
|
||
|
function isProxy(value) {
|
||
|
return isReactive(value) || isReadonly(value);
|
||
|
}
|
||
|
function toRaw(observed) {
|
||
|
const raw = observed && observed["__v_raw" /* RAW */];
|
||
|
return raw ? toRaw(raw) : observed;
|
||
|
}
|
||
|
function markRaw(value) {
|
||
|
def(value, "__v_skip" /* SKIP */, true);
|
||
|
return value;
|
||
|
}
|
||
|
const toReactive = (value) => isObject(value) ? reactive(value) : value;
|
||
|
const toReadonly = (value) => isObject(value) ? readonly(value) : value;
|
||
|
|
||
|
function trackRefValue(ref) {
|
||
|
if (shouldTrack && activeEffect) {
|
||
|
ref = toRaw(ref);
|
||
|
if ((process.env.NODE_ENV !== 'production')) {
|
||
|
trackEffects(ref.dep || (ref.dep = createDep()), {
|
||
|
target: ref,
|
||
|
type: "get" /* GET */,
|
||
|
key: 'value'
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
trackEffects(ref.dep || (ref.dep = createDep()));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function triggerRefValue(ref, newVal) {
|
||
|
ref = toRaw(ref);
|
||
|
if (ref.dep) {
|
||
|
if ((process.env.NODE_ENV !== 'production')) {
|
||
|
triggerEffects(ref.dep, {
|
||
|
target: ref,
|
||
|
type: "set" /* SET */,
|
||
|
key: 'value',
|
||
|
newValue: newVal
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
triggerEffects(ref.dep);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function isRef(r) {
|
||
|
return !!(r && r.__v_isRef === true);
|
||
|
}
|
||
|
function ref(value) {
|
||
|
return createRef(value, false);
|
||
|
}
|
||
|
function shallowRef(value) {
|
||
|
return createRef(value, true);
|
||
|
}
|
||
|
function createRef(rawValue, shallow) {
|
||
|
if (isRef(rawValue)) {
|
||
|
return rawValue;
|
||
|
}
|
||
|
return new RefImpl(rawValue, shallow);
|
||
|
}
|
||
|
class RefImpl {
|
||
|
constructor(value, __v_isShallow) {
|
||
|
this.__v_isShallow = __v_isShallow;
|
||
|
this.dep = undefined;
|
||
|
this.__v_isRef = true;
|
||
|
this._rawValue = __v_isShallow ? value : toRaw(value);
|
||
|
this._value = __v_isShallow ? value : toReactive(value);
|
||
|
}
|
||
|
get value() {
|
||
|
trackRefValue(this);
|
||
|
return this._value;
|
||
|
}
|
||
|
set value(newVal) {
|
||
|
newVal = this.__v_isShallow ? newVal : toRaw(newVal);
|
||
|
if (hasChanged(newVal, this._rawValue)) {
|
||
|
this._rawValue = newVal;
|
||
|
this._value = this.__v_isShallow ? newVal : toReactive(newVal);
|
||
|
triggerRefValue(this, newVal);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function triggerRef(ref) {
|
||
|
triggerRefValue(ref, (process.env.NODE_ENV !== 'production') ? ref.value : void 0);
|
||
|
}
|
||
|
function unref(ref) {
|
||
|
return isRef(ref) ? ref.value : ref;
|
||
|
}
|
||
|
const shallowUnwrapHandlers = {
|
||
|
get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)),
|
||
|
set: (target, key, value, receiver) => {
|
||
|
const oldValue = target[key];
|
||
|
if (isRef(oldValue) && !isRef(value)) {
|
||
|
oldValue.value = value;
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return Reflect.set(target, key, value, receiver);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
function proxyRefs(objectWithRefs) {
|
||
|
return isReactive(objectWithRefs)
|
||
|
? objectWithRefs
|
||
|
: new Proxy(objectWithRefs, shallowUnwrapHandlers);
|
||
|
}
|
||
|
class CustomRefImpl {
|
||
|
constructor(factory) {
|
||
|
this.dep = undefined;
|
||
|
this.__v_isRef = true;
|
||
|
const { get, set } = factory(() => trackRefValue(this), () => triggerRefValue(this));
|
||
|
this._get = get;
|
||
|
this._set = set;
|
||
|
}
|
||
|
get value() {
|
||
|
return this._get();
|
||
|
}
|
||
|
set value(newVal) {
|
||
|
this._set(newVal);
|
||
|
}
|
||
|
}
|
||
|
function customRef(factory) {
|
||
|
return new CustomRefImpl(factory);
|
||
|
}
|
||
|
function toRefs(object) {
|
||
|
if ((process.env.NODE_ENV !== 'production') && !isProxy(object)) {
|
||
|
console.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;
|
||
|
}
|
||
|
class ObjectRefImpl {
|
||
|
constructor(_object, _key, _defaultValue) {
|
||
|
this._object = _object;
|
||
|
this._key = _key;
|
||
|
this._defaultValue = _defaultValue;
|
||
|
this.__v_isRef = true;
|
||
|
}
|
||
|
get value() {
|
||
|
const val = this._object[this._key];
|
||
|
return val === undefined ? this._defaultValue : val;
|
||
|
}
|
||
|
set value(newVal) {
|
||
|
this._object[this._key] = newVal;
|
||
|
}
|
||
|
}
|
||
|
function toRef(object, key, defaultValue) {
|
||
|
const val = object[key];
|
||
|
return isRef(val)
|
||
|
? val
|
||
|
: new ObjectRefImpl(object, key, defaultValue);
|
||
|
}
|
||
|
|
||
|
class ComputedRefImpl {
|
||
|
constructor(getter, _setter, isReadonly, isSSR) {
|
||
|
this._setter = _setter;
|
||
|
this.dep = undefined;
|
||
|
this.__v_isRef = true;
|
||
|
this._dirty = true;
|
||
|
this.effect = new ReactiveEffect(getter, () => {
|
||
|
if (!this._dirty) {
|
||
|
this._dirty = true;
|
||
|
triggerRefValue(this);
|
||
|
}
|
||
|
});
|
||
|
this.effect.computed = this;
|
||
|
this.effect.active = this._cacheable = !isSSR;
|
||
|
this["__v_isReadonly" /* IS_READONLY */] = isReadonly;
|
||
|
}
|
||
|
get value() {
|
||
|
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
|
||
|
const self = toRaw(this);
|
||
|
trackRefValue(self);
|
||
|
if (self._dirty || !self._cacheable) {
|
||
|
self._dirty = false;
|
||
|
self._value = self.effect.run();
|
||
|
}
|
||
|
return self._value;
|
||
|
}
|
||
|
set value(newValue) {
|
||
|
this._setter(newValue);
|
||
|
}
|
||
|
}
|
||
|
function computed(getterOrOptions, debugOptions, isSSR = false) {
|
||
|
let getter;
|
||
|
let setter;
|
||
|
const onlyGetter = isFunction(getterOrOptions);
|
||
|
if (onlyGetter) {
|
||
|
getter = getterOrOptions;
|
||
|
setter = (process.env.NODE_ENV !== 'production')
|
||
|
? () => {
|
||
|
console.warn('Write operation failed: computed value is readonly');
|
||
|
}
|
||
|
: NOOP;
|
||
|
}
|
||
|
else {
|
||
|
getter = getterOrOptions.get;
|
||
|
setter = getterOrOptions.set;
|
||
|
}
|
||
|
const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
|
||
|
if ((process.env.NODE_ENV !== 'production') && debugOptions && !isSSR) {
|
||
|
cRef.effect.onTrack = debugOptions.onTrack;
|
||
|
cRef.effect.onTrigger = debugOptions.onTrigger;
|
||
|
}
|
||
|
return cRef;
|
||
|
}
|
||
|
|
||
|
var _a;
|
||
|
const tick = /*#__PURE__*/ Promise.resolve();
|
||
|
const queue = [];
|
||
|
let queued = false;
|
||
|
const scheduler = (fn) => {
|
||
|
queue.push(fn);
|
||
|
if (!queued) {
|
||
|
queued = true;
|
||
|
tick.then(flush);
|
||
|
}
|
||
|
};
|
||
|
const flush = () => {
|
||
|
for (let i = 0; i < queue.length; i++) {
|
||
|
queue[i]();
|
||
|
}
|
||
|
queue.length = 0;
|
||
|
queued = false;
|
||
|
};
|
||
|
class DeferredComputedRefImpl {
|
||
|
constructor(getter) {
|
||
|
this.dep = undefined;
|
||
|
this._dirty = true;
|
||
|
this.__v_isRef = true;
|
||
|
this[_a] = true;
|
||
|
let compareTarget;
|
||
|
let hasCompareTarget = false;
|
||
|
let scheduled = false;
|
||
|
this.effect = new ReactiveEffect(getter, (computedTrigger) => {
|
||
|
if (this.dep) {
|
||
|
if (computedTrigger) {
|
||
|
compareTarget = this._value;
|
||
|
hasCompareTarget = true;
|
||
|
}
|
||
|
else if (!scheduled) {
|
||
|
const valueToCompare = hasCompareTarget ? compareTarget : this._value;
|
||
|
scheduled = true;
|
||
|
hasCompareTarget = false;
|
||
|
scheduler(() => {
|
||
|
if (this.effect.active && this._get() !== valueToCompare) {
|
||
|
triggerRefValue(this);
|
||
|
}
|
||
|
scheduled = false;
|
||
|
});
|
||
|
}
|
||
|
// chained upstream computeds are notified synchronously to ensure
|
||
|
// value invalidation in case of sync access; normal effects are
|
||
|
// deferred to be triggered in scheduler.
|
||
|
for (const e of this.dep) {
|
||
|
if (e.computed instanceof DeferredComputedRefImpl) {
|
||
|
e.scheduler(true /* computedTrigger */);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
this._dirty = true;
|
||
|
});
|
||
|
this.effect.computed = this;
|
||
|
}
|
||
|
_get() {
|
||
|
if (this._dirty) {
|
||
|
this._dirty = false;
|
||
|
return (this._value = this.effect.run());
|
||
|
}
|
||
|
return this._value;
|
||
|
}
|
||
|
get value() {
|
||
|
trackRefValue(this);
|
||
|
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
|
||
|
return toRaw(this)._get();
|
||
|
}
|
||
|
}
|
||
|
_a = "__v_isReadonly" /* IS_READONLY */;
|
||
|
function deferredComputed(getter) {
|
||
|
return new DeferredComputedRefImpl(getter);
|
||
|
}
|
||
|
|
||
|
export { EffectScope, ITERATE_KEY, ReactiveEffect, computed, customRef, deferredComputed, effect, effectScope, enableTracking, getCurrentScope, isProxy, isReactive, isReadonly, isRef, isShallow, markRaw, onScopeDispose, pauseTracking, proxyRefs, reactive, readonly, ref, resetTracking, shallowReactive, shallowReadonly, shallowRef, stop, toRaw, toRef, toRefs, track, trigger, triggerRef, unref };
|