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