UNPKG

transmutable

Version:

immutable objects that pretend to be mutable

192 lines (165 loc) 7.24 kB
'use strict'; 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; }; function _defineProperty(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 _require = require('./symbols'), MUTATION = _require.MUTATION, WAS_WRITTEN = _require.WAS_WRITTEN, WAS_ACCESSED = _require.WAS_ACCESSED, ENTITY = _require.ENTITY, ENTITIES = _require.ENTITIES; var _require2 = require('./get-set'), _get = _require2.get, _set = _require2.set; var concatOne = function concatOne(arr, s) { var newArr = new Array(arr.length + 1); for (var i = 0; i <= arr.length; i++) { if (i < arr.length) newArr[i] = arr[i];else newArr[i] = s; } return newArr; }; var concat = concatOne; function createStage(target, rootPatch) { var keys = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; return new Proxy(target, { get: function get(target, name) { var propPatch = concat(keys, name); var value = void 0; var mutation = _get(rootPatch, concat(propPatch, MUTATION)); if (mutation) { return mutation.value; } else value = target[name]; if (value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) == 'object') { return createStage(value, rootPatch, propPatch); } return value; }, set: function set(target, name, value) { var oldValue = target[name]; if (value !== oldValue) { if (Array.isArray(target)) { var patch = _get(rootPatch, keys); if (!patch) { patch = {}; _set(rootPatch, keys, patch); } if (!patch[MUTATION]) { var arrayDraft = target.slice(); // we need to explicitly assign the first changed item // all next changes will affect arrayDraft directly // without Proxy (`get` trap will return patch[MUTATION].value) arrayDraft[name] = value; patch[MUTATION] = { value: arrayDraft }; } return true; } _set(rootPatch, concat(keys, name), _defineProperty({}, MUTATION, { value: value })); } return true; }, ownKeys: function ownKeys(target) { var patch = _get(rootPatch, keys.concat([])) || {}; return Array.from(new Set(Reflect.ownKeys(target).concat(Object.keys(patch)))); }, getOwnPropertyDescriptor: function getOwnPropertyDescriptor(target, name) { var patch = _get(rootPatch, keys) || {}; if (patch[name] && patch[name][MUTATION]) { return { configurable: true, enumerable: true, value: patch[name][MUTATION].value }; } return Reflect.getOwnPropertyDescriptor(target, name); } }); } function applyPatch(node, patch, root, rootPatch) { if (patch && patch[MUTATION]) { var mutValue = patch[MUTATION].value; if (mutValue && mutValue[ENTITY]) { var id = mutValue[ENTITY]; if (rootPatch[ENTITIES] && rootPatch[ENTITIES] && rootPatch[ENTITIES][id]) { return rootPatch[ENTITIES][id][MUTATION].value; } return root[ENTITIES][mutValue[ENTITY]]; } return patch[MUTATION].value; } var symbols = void 0; if (node && (typeof node === 'undefined' ? 'undefined' : _typeof(node)) == 'object') { symbols = Object.getOwnPropertySymbols(node); } if (patch && node && (typeof node === 'undefined' ? 'undefined' : _typeof(node)) == 'object' //&& patch[WAS_ACCESSED] && Object.keys(patch).length || symbols && symbols.length) { var copy = void 0; if (Array.isArray(node)) copy = node.slice();else { copy = {}; for (var k in node) { copy[k] = node[k]; } if (symbols) { for (var i = 0; i < symbols.length; i++) { copy[symbols[i]] = node[symbols[i]]; } } } for (var _k in patch) { var res = applyPatch(node[_k], patch[_k], root, rootPatch); copy[_k] = res; } var patchSymbols = Object.getOwnPropertySymbols(patch); for (var _i = 0; _i < patchSymbols.length; _i++) { var _k2 = patchSymbols[_i]; var _res = applyPatch(node[_k2], patch[_k2], root, rootPatch); copy[_k2] = _res; } return copy; } return node; } exports.applyPatch = applyPatch; var diff = require('./diff'); var copyDeep = require('./copyDeep'); var transform = function transform(transformer, original) { for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } if (typeof original == 'undefined') { return transform.bind(null, transformer); } if (typeof transformer !== 'function') throw new Error('\n API was changed in 0.5.0 version of Transmutable library.\n Now transform function takes transforming function as a FIRST argument.\n Original state as a SECOND one.\n '); var patch = void 0; var result = void 0; if (typeof Proxy == 'undefined') { var copy = copyDeep(original); result = transformer.call.apply(transformer, [copy, copy].concat(args)); patch = diff(original, copy); } else { patch = {}; var stage = createStage(original, patch); result = transformer.call.apply(transformer, [stage, stage].concat(args)); } if (typeof result != 'undefined') return result; return applyPatch(original, patch, original, patch); }; exports.transform = transform; // we keep Reducer separately because Reducer is meant for use with Redux // and Transform is for general use. // now they both share the same API and implementation // but in future versions it may not be true exports.Reducer = function () { throw new Error("Transmutable: to create Redux reducer just use `transform` function with currying (look into docs)"); }; var over = function over(getter, setter, original) { if (typeof setter == 'undefined') return over.bind(null, getter); return transform(function (d) { var relativeStage = _get(d, getter); var result = setter.call(relativeStage, relativeStage); if (typeof result != 'undefined') { _set(d, getter, result); } }, original); }; exports.over = over; exports.transformAt = over;