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.
881 lines
30 KiB
881 lines
30 KiB
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
|
|
|