882 lines
30 KiB
JavaScript
882 lines
30 KiB
JavaScript
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
||
|
return typeof obj;
|
||
|
} : function (obj) {
|
||
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
var classCallCheck = function (instance, Constructor) {
|
||
|
if (!(instance instanceof Constructor)) {
|
||
|
throw new TypeError("Cannot call a class as a function");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var createClass = function () {
|
||
|
function defineProperties(target, props) {
|
||
|
for (var i = 0; i < props.length; i++) {
|
||
|
var descriptor = props[i];
|
||
|
descriptor.enumerable = descriptor.enumerable || false;
|
||
|
descriptor.configurable = true;
|
||
|
if ("value" in descriptor) descriptor.writable = true;
|
||
|
Object.defineProperty(target, descriptor.key, descriptor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return function (Constructor, protoProps, staticProps) {
|
||
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||
|
if (staticProps) defineProperties(Constructor, staticProps);
|
||
|
return Constructor;
|
||
|
};
|
||
|
}();
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
var defineProperty = function (obj, key, value) {
|
||
|
if (key in obj) {
|
||
|
Object.defineProperty(obj, key, {
|
||
|
value: value,
|
||
|
enumerable: true,
|
||
|
configurable: true,
|
||
|
writable: true
|
||
|
});
|
||
|
} else {
|
||
|
obj[key] = value;
|
||
|
}
|
||
|
|
||
|
return obj;
|
||
|
};
|
||
|
|
||
|
var NOTHING = typeof Symbol !== "undefined" ? Symbol("immer-nothing") : defineProperty({}, "immer-nothing", true);
|
||
|
|
||
|
var DRAFT_STATE = typeof Symbol !== "undefined" ? Symbol("immer-state") : "__$immer_state";
|
||
|
|
||
|
function isDraft(value) {
|
||
|
return !!value && !!value[DRAFT_STATE];
|
||
|
}
|
||
|
|
||
|
function isDraftable(value) {
|
||
|
if (!value) return false;
|
||
|
if ((typeof value === "undefined" ? "undefined" : _typeof(value)) !== "object") return false;
|
||
|
if (Array.isArray(value)) return true;
|
||
|
var proto = Object.getPrototypeOf(value);
|
||
|
return proto === null || proto === Object.prototype;
|
||
|
}
|
||
|
|
||
|
function original(value) {
|
||
|
if (value && value[DRAFT_STATE]) {
|
||
|
return value[DRAFT_STATE].base;
|
||
|
}
|
||
|
// otherwise return undefined
|
||
|
}
|
||
|
|
||
|
var assign = Object.assign || function assign(target, value) {
|
||
|
for (var key in value) {
|
||
|
if (has(value, key)) {
|
||
|
target[key] = value[key];
|
||
|
}
|
||
|
}
|
||
|
return target;
|
||
|
};
|
||
|
|
||
|
function shallowCopy(value) {
|
||
|
if (Array.isArray(value)) return value.slice();
|
||
|
var target = value.__proto__ === undefined ? Object.create(null) : {};
|
||
|
return assign(target, value);
|
||
|
}
|
||
|
|
||
|
function each(value, cb) {
|
||
|
if (Array.isArray(value)) {
|
||
|
for (var i = 0; i < value.length; i++) {
|
||
|
cb(i, value[i], value);
|
||
|
}
|
||
|
} else {
|
||
|
for (var key in value) {
|
||
|
cb(key, value[key], value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function has(thing, prop) {
|
||
|
return Object.prototype.hasOwnProperty.call(thing, prop);
|
||
|
}
|
||
|
|
||
|
function is(x, y) {
|
||
|
// From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
|
||
|
if (x === y) {
|
||
|
return x !== 0 || 1 / x === 1 / y;
|
||
|
} else {
|
||
|
return x !== x && y !== y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function generatePatches(state, basePath, patches, inversePatches) {
|
||
|
Array.isArray(state.base) ? generateArrayPatches(state, basePath, patches, inversePatches) : generateObjectPatches(state, basePath, patches, inversePatches);
|
||
|
}
|
||
|
|
||
|
function generateArrayPatches(state, basePath, patches, inversePatches) {
|
||
|
var base = state.base,
|
||
|
copy = state.copy,
|
||
|
assigned = state.assigned;
|
||
|
|
||
|
var minLength = Math.min(base.length, copy.length);
|
||
|
|
||
|
// Look for replaced indices.
|
||
|
for (var i = 0; i < minLength; i++) {
|
||
|
if (assigned[i] && base[i] !== copy[i]) {
|
||
|
var path = basePath.concat(i);
|
||
|
patches.push({ op: "replace", path: path, value: copy[i] });
|
||
|
inversePatches.push({ op: "replace", path: path, value: base[i] });
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Did the array expand?
|
||
|
if (minLength < copy.length) {
|
||
|
for (var _i = minLength; _i < copy.length; _i++) {
|
||
|
patches.push({
|
||
|
op: "add",
|
||
|
path: basePath.concat(_i),
|
||
|
value: copy[_i]
|
||
|
});
|
||
|
}
|
||
|
inversePatches.push({
|
||
|
op: "replace",
|
||
|
path: basePath.concat("length"),
|
||
|
value: base.length
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// ...or did it shrink?
|
||
|
else if (minLength < base.length) {
|
||
|
patches.push({
|
||
|
op: "replace",
|
||
|
path: basePath.concat("length"),
|
||
|
value: copy.length
|
||
|
});
|
||
|
for (var _i2 = minLength; _i2 < base.length; _i2++) {
|
||
|
inversePatches.push({
|
||
|
op: "add",
|
||
|
path: basePath.concat(_i2),
|
||
|
value: base[_i2]
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function generateObjectPatches(state, basePath, patches, inversePatches) {
|
||
|
var base = state.base,
|
||
|
copy = state.copy;
|
||
|
|
||
|
each(state.assigned, function (key, assignedValue) {
|
||
|
var origValue = base[key];
|
||
|
var value = copy[key];
|
||
|
var op = !assignedValue ? "remove" : key in base ? "replace" : "add";
|
||
|
if (origValue === base && op === "replace") return;
|
||
|
var path = basePath.concat(key);
|
||
|
patches.push(op === "remove" ? { op: op, path: path } : { op: op, path: path, value: value });
|
||
|
inversePatches.push(op === "add" ? { op: "remove", path: path } : op === "remove" ? { op: "add", path: path, value: origValue } : { op: "replace", path: path, value: origValue });
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function applyPatches(draft, patches) {
|
||
|
for (var i = 0; i < patches.length; i++) {
|
||
|
var patch = patches[i];
|
||
|
var path = patch.path;
|
||
|
|
||
|
if (path.length === 0 && patch.op === "replace") {
|
||
|
draft = patch.value;
|
||
|
} else {
|
||
|
var base = draft;
|
||
|
for (var _i3 = 0; _i3 < path.length - 1; _i3++) {
|
||
|
base = base[path[_i3]];
|
||
|
if (!base || (typeof base === "undefined" ? "undefined" : _typeof(base)) !== "object") throw new Error("Cannot apply patch, path doesn't resolve: " + path.join("/")); // prettier-ignore
|
||
|
}
|
||
|
var key = path[path.length - 1];
|
||
|
switch (patch.op) {
|
||
|
case "replace":
|
||
|
case "add":
|
||
|
// TODO: add support is not extensive, it does not support insertion or `-` atm!
|
||
|
base[key] = patch.value;
|
||
|
break;
|
||
|
case "remove":
|
||
|
if (Array.isArray(base)) {
|
||
|
if (key !== base.length - 1) throw new Error("Only the last index of an array can be removed, index: " + key + ", length: " + base.length); // prettier-ignore
|
||
|
base.length -= 1;
|
||
|
} else {
|
||
|
delete base[key];
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
throw new Error("Unsupported patch operation: " + patch.op);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return draft;
|
||
|
}
|
||
|
|
||
|
// @ts-check
|
||
|
|
||
|
var descriptors = {};
|
||
|
|
||
|
// For nested produce calls:
|
||
|
var scopes = [];
|
||
|
var currentScope = function currentScope() {
|
||
|
return scopes[scopes.length - 1];
|
||
|
};
|
||
|
|
||
|
function willFinalize(result, baseDraft, needPatches) {
|
||
|
var scope = currentScope();
|
||
|
scope.forEach(function (state) {
|
||
|
return state.finalizing = true;
|
||
|
});
|
||
|
if (result === undefined || result === baseDraft) {
|
||
|
if (needPatches) markChangesRecursively(baseDraft);
|
||
|
// This is faster when we don't care about which attributes changed.
|
||
|
markChangesSweep(scope);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function createDraft(base, parent) {
|
||
|
var draft = void 0;
|
||
|
if (isDraft(base)) {
|
||
|
var _state = base[DRAFT_STATE];
|
||
|
// Avoid creating new drafts when copying.
|
||
|
_state.finalizing = true;
|
||
|
draft = shallowCopy(_state.draft);
|
||
|
_state.finalizing = false;
|
||
|
} else {
|
||
|
draft = shallowCopy(base);
|
||
|
}
|
||
|
each(base, function (prop) {
|
||
|
Object.defineProperty(draft, "" + prop, createPropertyProxy("" + prop));
|
||
|
});
|
||
|
|
||
|
// See "proxy.js" for property documentation.
|
||
|
var state = {
|
||
|
scope: parent ? parent.scope : currentScope(),
|
||
|
modified: false,
|
||
|
finalizing: false, // es5 only
|
||
|
finalized: false,
|
||
|
assigned: {},
|
||
|
parent: parent,
|
||
|
base: base,
|
||
|
draft: draft,
|
||
|
copy: null,
|
||
|
revoke: revoke,
|
||
|
revoked: false // es5 only
|
||
|
};
|
||
|
|
||
|
createHiddenProperty(draft, DRAFT_STATE, state);
|
||
|
state.scope.push(state);
|
||
|
return draft;
|
||
|
}
|
||
|
|
||
|
function revoke() {
|
||
|
this.revoked = true;
|
||
|
}
|
||
|
|
||
|
function source(state) {
|
||
|
return state.copy || state.base;
|
||
|
}
|
||
|
|
||
|
function _get(state, prop) {
|
||
|
assertUnrevoked(state);
|
||
|
var value = source(state)[prop];
|
||
|
// Drafts are only created for proxyable values that exist in the base state.
|
||
|
if (!state.finalizing && value === state.base[prop] && isDraftable(value)) {
|
||
|
prepareCopy(state);
|
||
|
return state.copy[prop] = createDraft(value, state);
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
function _set(state, prop, value) {
|
||
|
assertUnrevoked(state);
|
||
|
state.assigned[prop] = true;
|
||
|
if (!state.modified) {
|
||
|
if (is(source(state)[prop], value)) return;
|
||
|
markChanged(state);
|
||
|
prepareCopy(state);
|
||
|
}
|
||
|
state.copy[prop] = value;
|
||
|
}
|
||
|
|
||
|
function markChanged(state) {
|
||
|
if (!state.modified) {
|
||
|
state.modified = true;
|
||
|
if (state.parent) markChanged(state.parent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function prepareCopy(state) {
|
||
|
if (!state.copy) state.copy = shallowCopy(state.base);
|
||
|
}
|
||
|
|
||
|
function createPropertyProxy(prop) {
|
||
|
return descriptors[prop] || (descriptors[prop] = {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function get$$1() {
|
||
|
return _get(this[DRAFT_STATE], prop);
|
||
|
},
|
||
|
set: function set$$1(value) {
|
||
|
_set(this[DRAFT_STATE], prop, value);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function assertUnrevoked(state) {
|
||
|
if (state.revoked === true) throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? " + JSON.stringify(state.copy || state.base));
|
||
|
}
|
||
|
|
||
|
// This looks expensive, but only proxies are visited, and only objects without known changes are scanned.
|
||
|
function markChangesSweep(scope) {
|
||
|
// The natural order of drafts in the `scope` array is based on when they
|
||
|
// were accessed. By processing drafts in reverse natural order, we have a
|
||
|
// better chance of processing leaf nodes first. When a leaf node is known to
|
||
|
// have changed, we can avoid any traversal of its ancestor nodes.
|
||
|
for (var i = scope.length - 1; i >= 0; i--) {
|
||
|
var state = scope[i];
|
||
|
if (state.modified === false) {
|
||
|
if (Array.isArray(state.base)) {
|
||
|
if (hasArrayChanges(state)) markChanged(state);
|
||
|
} else if (hasObjectChanges(state)) markChanged(state);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function markChangesRecursively(object) {
|
||
|
if (!object || (typeof object === "undefined" ? "undefined" : _typeof(object)) !== "object") return;
|
||
|
var state = object[DRAFT_STATE];
|
||
|
if (!state) return;
|
||
|
var base = state.base,
|
||
|
draft = state.draft,
|
||
|
assigned = state.assigned;
|
||
|
|
||
|
if (!Array.isArray(object)) {
|
||
|
// Look for added keys.
|
||
|
Object.keys(draft).forEach(function (key) {
|
||
|
// The `undefined` check is a fast path for pre-existing keys.
|
||
|
if (base[key] === undefined && !has(base, key)) {
|
||
|
assigned[key] = true;
|
||
|
markChanged(state);
|
||
|
} else if (!assigned[key]) {
|
||
|
// Only untouched properties trigger recursion.
|
||
|
markChangesRecursively(draft[key]);
|
||
|
}
|
||
|
});
|
||
|
// Look for removed keys.
|
||
|
Object.keys(base).forEach(function (key) {
|
||
|
// The `undefined` check is a fast path for pre-existing keys.
|
||
|
if (draft[key] === undefined && !has(draft, key)) {
|
||
|
assigned[key] = false;
|
||
|
markChanged(state);
|
||
|
}
|
||
|
});
|
||
|
} else if (hasArrayChanges(state)) {
|
||
|
markChanged(state);
|
||
|
assigned.length = true;
|
||
|
if (draft.length < base.length) {
|
||
|
for (var i = draft.length; i < base.length; i++) {
|
||
|
assigned[i] = false;
|
||
|
}
|
||
|
} else {
|
||
|
for (var _i = base.length; _i < draft.length; _i++) {
|
||
|
assigned[_i] = true;
|
||
|
}
|
||
|
}
|
||
|
for (var _i2 = 0; _i2 < draft.length; _i2++) {
|
||
|
// Only untouched indices trigger recursion.
|
||
|
if (assigned[_i2] === undefined) markChangesRecursively(draft[_i2]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function hasObjectChanges(state) {
|
||
|
var base = state.base,
|
||
|
draft = state.draft;
|
||
|
|
||
|
// Search for added keys. Start at the back, because non-numeric keys
|
||
|
// are ordered by time of definition on the object.
|
||
|
|
||
|
var keys = Object.keys(draft);
|
||
|
for (var i = keys.length - 1; i >= 0; i--) {
|
||
|
// The `undefined` check is a fast path for pre-existing keys.
|
||
|
if (base[keys[i]] === undefined && !has(base, keys[i])) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Since no keys have been added, we can compare lengths to know if an
|
||
|
// object has been deleted.
|
||
|
return keys.length !== Object.keys(base).length;
|
||
|
}
|
||
|
|
||
|
function hasArrayChanges(state) {
|
||
|
var draft = state.draft;
|
||
|
|
||
|
if (draft.length !== state.base.length) return true;
|
||
|
// See #116
|
||
|
// If we first shorten the length, our array interceptors will be removed.
|
||
|
// If after that new items are added, result in the same original length,
|
||
|
// those last items will have no intercepting property.
|
||
|
// So if there is no own descriptor on the last position, we know that items were removed and added
|
||
|
// N.B.: splice, unshift, etc only shift values around, but not prop descriptors, so we only have to check
|
||
|
// the last one
|
||
|
var descriptor = Object.getOwnPropertyDescriptor(draft, draft.length - 1);
|
||
|
// descriptor can be null, but only for newly created sparse arrays, eg. new Array(10)
|
||
|
if (descriptor && !descriptor.get) return true;
|
||
|
// For all other cases, we don't have to compare, as they would have been picked up by the index setters
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function createHiddenProperty(target, prop, value) {
|
||
|
Object.defineProperty(target, prop, {
|
||
|
value: value,
|
||
|
enumerable: false,
|
||
|
writable: true
|
||
|
});
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
var legacyProxy = Object.freeze({
|
||
|
scopes: scopes,
|
||
|
currentScope: currentScope,
|
||
|
willFinalize: willFinalize,
|
||
|
createDraft: createDraft
|
||
|
});
|
||
|
|
||
|
// @ts-check
|
||
|
|
||
|
// For nested produce calls:
|
||
|
var scopes$1 = [];
|
||
|
var currentScope$1 = function currentScope() {
|
||
|
return scopes$1[scopes$1.length - 1];
|
||
|
};
|
||
|
|
||
|
// Do nothing before being finalized.
|
||
|
function willFinalize$1() {}
|
||
|
|
||
|
function createDraft$1(base, parent) {
|
||
|
var state = {
|
||
|
// Track which produce call this is associated with.
|
||
|
scope: parent ? parent.scope : currentScope$1(),
|
||
|
// True for both shallow and deep changes.
|
||
|
modified: false,
|
||
|
// Used during finalization.
|
||
|
finalized: false,
|
||
|
// Track which properties have been assigned (true) or deleted (false).
|
||
|
assigned: {},
|
||
|
// The parent draft state.
|
||
|
parent: parent,
|
||
|
// The base state.
|
||
|
base: base,
|
||
|
// The base proxy.
|
||
|
draft: null,
|
||
|
// Any property proxies.
|
||
|
drafts: {},
|
||
|
// The base copy with any updated values.
|
||
|
copy: null,
|
||
|
// Called by the `produce` function.
|
||
|
revoke: null
|
||
|
};
|
||
|
|
||
|
var _ref = Array.isArray(base) ? Proxy.revocable([state], arrayTraps) : Proxy.revocable(state, objectTraps),
|
||
|
revoke = _ref.revoke,
|
||
|
proxy = _ref.proxy;
|
||
|
|
||
|
state.draft = proxy;
|
||
|
state.revoke = revoke;
|
||
|
|
||
|
state.scope.push(state);
|
||
|
return proxy;
|
||
|
}
|
||
|
|
||
|
var objectTraps = {
|
||
|
get: get$1,
|
||
|
has: function has$$1(target, prop) {
|
||
|
return prop in source$1(target);
|
||
|
},
|
||
|
ownKeys: function ownKeys(target) {
|
||
|
return Reflect.ownKeys(source$1(target));
|
||
|
},
|
||
|
|
||
|
set: set$1,
|
||
|
deleteProperty: deleteProperty,
|
||
|
getOwnPropertyDescriptor: getOwnPropertyDescriptor,
|
||
|
defineProperty: defineProperty$1,
|
||
|
setPrototypeOf: function setPrototypeOf() {
|
||
|
throw new Error("Immer does not support `setPrototypeOf()`.");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var arrayTraps = {};
|
||
|
each(objectTraps, function (key, fn) {
|
||
|
arrayTraps[key] = function () {
|
||
|
arguments[0] = arguments[0][0];
|
||
|
return fn.apply(this, arguments);
|
||
|
};
|
||
|
});
|
||
|
arrayTraps.deleteProperty = function (state, prop) {
|
||
|
if (isNaN(parseInt(prop))) throw new Error("Immer does not support deleting properties from arrays: " + prop);
|
||
|
return objectTraps.deleteProperty.call(this, state[0], prop);
|
||
|
};
|
||
|
arrayTraps.set = function (state, prop, value) {
|
||
|
if (prop !== "length" && isNaN(parseInt(prop))) throw new Error("Immer does not support setting non-numeric properties on arrays: " + prop);
|
||
|
return objectTraps.set.call(this, state[0], prop, value);
|
||
|
};
|
||
|
|
||
|
function source$1(state) {
|
||
|
return state.copy || state.base;
|
||
|
}
|
||
|
|
||
|
function get$1(state, prop) {
|
||
|
if (prop === DRAFT_STATE) return state;
|
||
|
var drafts = state.drafts;
|
||
|
|
||
|
// Check for existing draft in unmodified state.
|
||
|
|
||
|
if (!state.modified && has(drafts, prop)) {
|
||
|
return drafts[prop];
|
||
|
}
|
||
|
|
||
|
var value = source$1(state)[prop];
|
||
|
if (state.finalized || !isDraftable(value)) return value;
|
||
|
|
||
|
// Check for existing draft in modified state.
|
||
|
if (state.modified) {
|
||
|
// Assigned values are never drafted. This catches any drafts we created, too.
|
||
|
if (value !== state.base[prop]) return value;
|
||
|
// Store drafts on the copy (when one exists).
|
||
|
drafts = state.copy;
|
||
|
}
|
||
|
|
||
|
return drafts[prop] = createDraft$1(value, state);
|
||
|
}
|
||
|
|
||
|
function set$1(state, prop, value) {
|
||
|
if (!state.modified) {
|
||
|
// Optimize based on value's truthiness. Truthy values are guaranteed to
|
||
|
// never be undefined, so we can avoid the `in` operator. Lastly, truthy
|
||
|
// values may be drafts, but falsy values are never drafts.
|
||
|
var isUnchanged = value ? is(state.base[prop], value) || value === state.drafts[prop] : is(state.base[prop], value) && prop in state.base;
|
||
|
if (isUnchanged) return true;
|
||
|
markChanged$1(state);
|
||
|
}
|
||
|
state.assigned[prop] = true;
|
||
|
state.copy[prop] = value;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function deleteProperty(state, prop) {
|
||
|
// The `undefined` check is a fast path for pre-existing keys.
|
||
|
if (state.base[prop] !== undefined || prop in state.base) {
|
||
|
state.assigned[prop] = false;
|
||
|
markChanged$1(state);
|
||
|
}
|
||
|
if (state.copy) delete state.copy[prop];
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function getOwnPropertyDescriptor(state, prop) {
|
||
|
var owner = state.modified ? state.copy : has(state.drafts, prop) ? state.drafts : state.base;
|
||
|
var descriptor = Reflect.getOwnPropertyDescriptor(owner, prop);
|
||
|
if (descriptor && !(Array.isArray(owner) && prop === "length")) descriptor.configurable = true;
|
||
|
return descriptor;
|
||
|
}
|
||
|
|
||
|
function defineProperty$1() {
|
||
|
throw new Error("Immer does not support defining properties on draft objects.");
|
||
|
}
|
||
|
|
||
|
function markChanged$1(state) {
|
||
|
if (!state.modified) {
|
||
|
state.modified = true;
|
||
|
state.copy = assign(shallowCopy(state.base), state.drafts);
|
||
|
state.drafts = null;
|
||
|
if (state.parent) markChanged$1(state.parent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var modernProxy = Object.freeze({
|
||
|
scopes: scopes$1,
|
||
|
currentScope: currentScope$1,
|
||
|
willFinalize: willFinalize$1,
|
||
|
createDraft: createDraft$1
|
||
|
});
|
||
|
|
||
|
function verifyMinified() {}
|
||
|
|
||
|
var configDefaults = {
|
||
|
useProxies: typeof Proxy !== "undefined" && typeof Reflect !== "undefined",
|
||
|
autoFreeze: typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : verifyMinified.name === "verifyMinified",
|
||
|
onAssign: null,
|
||
|
onDelete: null,
|
||
|
onCopy: null
|
||
|
};
|
||
|
|
||
|
var Immer = function () {
|
||
|
function Immer(config) {
|
||
|
classCallCheck(this, Immer);
|
||
|
|
||
|
assign(this, configDefaults, config);
|
||
|
this.setUseProxies(this.useProxies);
|
||
|
this.produce = this.produce.bind(this);
|
||
|
}
|
||
|
|
||
|
createClass(Immer, [{
|
||
|
key: "produce",
|
||
|
value: function produce(base, recipe, patchListener) {
|
||
|
var _this = this;
|
||
|
|
||
|
// curried invocation
|
||
|
if (typeof base === "function" && typeof recipe !== "function") {
|
||
|
var defaultBase = recipe;
|
||
|
recipe = base;
|
||
|
|
||
|
// prettier-ignore
|
||
|
return function () {
|
||
|
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||
|
args[_key - 1] = arguments[_key];
|
||
|
}
|
||
|
|
||
|
var base = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultBase;
|
||
|
return _this.produce(base, function (draft) {
|
||
|
var _recipe;
|
||
|
|
||
|
return (_recipe = recipe).call.apply(_recipe, [draft, draft].concat(args));
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// prettier-ignore
|
||
|
{
|
||
|
if (typeof recipe !== "function") throw new Error("if first argument is not a function, the second argument to produce should be a function");
|
||
|
if (patchListener !== undefined && typeof patchListener !== "function") throw new Error("the third argument of a producer should not be set or a function");
|
||
|
}
|
||
|
|
||
|
var result = void 0;
|
||
|
// Only create proxies for plain objects/arrays.
|
||
|
if (!isDraftable(base)) {
|
||
|
result = recipe(base);
|
||
|
if (result === undefined) return base;
|
||
|
}
|
||
|
// See #100, don't nest producers
|
||
|
else if (isDraft(base)) {
|
||
|
result = recipe.call(base, base);
|
||
|
if (result === undefined) return base;
|
||
|
}
|
||
|
// The given value must be proxied.
|
||
|
else {
|
||
|
this.scopes.push([]);
|
||
|
var baseDraft = this.createDraft(base);
|
||
|
try {
|
||
|
result = recipe.call(baseDraft, baseDraft);
|
||
|
this.willFinalize(result, baseDraft, !!patchListener);
|
||
|
|
||
|
// Never generate patches when no listener exists.
|
||
|
var patches = patchListener && [],
|
||
|
inversePatches = patchListener && [];
|
||
|
|
||
|
// Finalize the modified draft...
|
||
|
if (result === undefined || result === baseDraft) {
|
||
|
result = this.finalize(baseDraft, [], patches, inversePatches);
|
||
|
}
|
||
|
// ...or use a replacement value.
|
||
|
else {
|
||
|
// Users must never modify the draft _and_ return something else.
|
||
|
if (baseDraft[DRAFT_STATE].modified) throw new Error("An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."); // prettier-ignore
|
||
|
|
||
|
// Finalize the replacement in case it contains (or is) a subset of the draft.
|
||
|
if (isDraftable(result)) result = this.finalize(result);
|
||
|
|
||
|
if (patchListener) {
|
||
|
patches.push({
|
||
|
op: "replace",
|
||
|
path: [],
|
||
|
value: result
|
||
|
});
|
||
|
inversePatches.push({
|
||
|
op: "replace",
|
||
|
path: [],
|
||
|
value: base
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
} finally {
|
||
|
this.currentScope().forEach(function (state) {
|
||
|
return state.revoke();
|
||
|
});
|
||
|
this.scopes.pop();
|
||
|
}
|
||
|
patchListener && patchListener(patches, inversePatches);
|
||
|
}
|
||
|
// Normalize the result.
|
||
|
return result === NOTHING ? undefined : result;
|
||
|
}
|
||
|
}, {
|
||
|
key: "setAutoFreeze",
|
||
|
value: function setAutoFreeze(value) {
|
||
|
this.autoFreeze = value;
|
||
|
}
|
||
|
}, {
|
||
|
key: "setUseProxies",
|
||
|
value: function setUseProxies(value) {
|
||
|
this.useProxies = value;
|
||
|
assign(this, value ? modernProxy : legacyProxy);
|
||
|
}
|
||
|
/**
|
||
|
* @internal
|
||
|
* Finalize a draft, returning either the unmodified base state or a modified
|
||
|
* copy of the base state.
|
||
|
*/
|
||
|
|
||
|
}, {
|
||
|
key: "finalize",
|
||
|
value: function finalize(draft, path, patches, inversePatches) {
|
||
|
var state = draft[DRAFT_STATE];
|
||
|
if (!state) {
|
||
|
if (Object.isFrozen(draft)) return draft;
|
||
|
return this.finalizeTree(draft);
|
||
|
}
|
||
|
// Never finalize drafts owned by an outer scope.
|
||
|
if (state.scope !== this.currentScope()) {
|
||
|
return draft;
|
||
|
}
|
||
|
if (!state.modified) return state.base;
|
||
|
if (!state.finalized) {
|
||
|
state.finalized = true;
|
||
|
this.finalizeTree(state.draft, path, patches, inversePatches);
|
||
|
if (this.onDelete) {
|
||
|
var assigned = state.assigned;
|
||
|
|
||
|
for (var prop in assigned) {
|
||
|
assigned[prop] || this.onDelete(state, prop);
|
||
|
}
|
||
|
}
|
||
|
if (this.onCopy) this.onCopy(state);
|
||
|
|
||
|
// Nested producers must never auto-freeze their result,
|
||
|
// because it may contain drafts from parent producers.
|
||
|
if (this.autoFreeze && this.scopes.length === 1) {
|
||
|
Object.freeze(state.copy);
|
||
|
}
|
||
|
|
||
|
if (patches) generatePatches(state, path, patches, inversePatches);
|
||
|
}
|
||
|
return state.copy;
|
||
|
}
|
||
|
/**
|
||
|
* @internal
|
||
|
* Finalize all drafts in the given state tree.
|
||
|
*/
|
||
|
|
||
|
}, {
|
||
|
key: "finalizeTree",
|
||
|
value: function finalizeTree(root, path, patches, inversePatches) {
|
||
|
var _this2 = this;
|
||
|
|
||
|
var state = root[DRAFT_STATE];
|
||
|
if (state) {
|
||
|
root = this.useProxies ? state.copy : state.copy = shallowCopy(state.draft);
|
||
|
}
|
||
|
|
||
|
var onAssign = this.onAssign;
|
||
|
|
||
|
var finalizeProperty = function finalizeProperty(prop, value, parent) {
|
||
|
// Only `root` can be a draft in here.
|
||
|
var inDraft = !!state && parent === root;
|
||
|
|
||
|
if (isDraft(value)) {
|
||
|
// prettier-ignore
|
||
|
parent[prop] = value =
|
||
|
// Patches are never generated for assigned properties.
|
||
|
patches && inDraft && !state.assigned[prop] ? _this2.finalize(value, path.concat(prop), patches, inversePatches) : _this2.finalize(value);
|
||
|
|
||
|
// Unchanged drafts are ignored.
|
||
|
if (inDraft && value === state.base[prop]) return;
|
||
|
}
|
||
|
// Unchanged draft properties are ignored.
|
||
|
else if (inDraft && is(value, state.base[prop])) {
|
||
|
return;
|
||
|
}
|
||
|
// Search new objects for unfinalized drafts. Frozen objects should never contain drafts.
|
||
|
else if (isDraftable(value) && !Object.isFrozen(value)) {
|
||
|
each(value, finalizeProperty);
|
||
|
}
|
||
|
|
||
|
if (inDraft && onAssign) {
|
||
|
onAssign(state, prop, value);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
each(root, finalizeProperty);
|
||
|
return root;
|
||
|
}
|
||
|
}]);
|
||
|
return Immer;
|
||
|
}();
|
||
|
|
||
|
var immer = new Immer();
|
||
|
|
||
|
/**
|
||
|
* The `produce` function takes a value and a "recipe function" (whose
|
||
|
* return value often depends on the base state). The recipe function is
|
||
|
* free to mutate its first argument however it wants. All mutations are
|
||
|
* only ever applied to a __copy__ of the base state.
|
||
|
*
|
||
|
* Pass only a function to create a "curried producer" which relieves you
|
||
|
* from passing the recipe function every time.
|
||
|
*
|
||
|
* Only plain objects and arrays are made mutable. All other objects are
|
||
|
* considered uncopyable.
|
||
|
*
|
||
|
* Note: This function is __bound__ to its `Immer` instance.
|
||
|
*
|
||
|
* @param {any} base - the initial state
|
||
|
* @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
|
||
|
* @param {Function} patchListener - optional function that will be called with all the patches produced here
|
||
|
* @returns {any} a new state, or the initial state if nothing was modified
|
||
|
*/
|
||
|
var produce = immer.produce;
|
||
|
/**
|
||
|
* Pass true to automatically freeze all copies created by Immer.
|
||
|
*
|
||
|
* By default, auto-freezing is disabled in production.
|
||
|
*/
|
||
|
var setAutoFreeze = function setAutoFreeze(value) {
|
||
|
return immer.setAutoFreeze(value);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Pass true to use the ES2015 `Proxy` class when creating drafts, which is
|
||
|
* always faster than using ES5 proxies.
|
||
|
*
|
||
|
* By default, feature detection is used, so calling this is rarely necessary.
|
||
|
*/
|
||
|
var setUseProxies = function setUseProxies(value) {
|
||
|
return immer.setUseProxies(value);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Apply an array of Immer patches to the first argument.
|
||
|
*
|
||
|
* This function is a producer, which means copy-on-write is in effect.
|
||
|
*/
|
||
|
var applyPatches$1 = produce(applyPatches);
|
||
|
|
||
|
export { produce, setAutoFreeze, setUseProxies, applyPatches$1 as applyPatches, Immer, original, isDraft, NOTHING as nothing };
|
||
|
export default produce;
|
||
|
//# sourceMappingURL=immer.module.js.map
|