UNPKG

ion

Version:

ion language ========================

477 lines 20.5 kB
void (function(){var _ion_mergePatch_ = function(module,exports,require){'use strict'; var ion = require('./'), isObject = function (a) { var type = typeof a; return a != null && type === 'object' || type === 'function'; }, deleteValue = null, isPrivate = function (name) { return name[0] === '_'; }, watchImmediate = function (object, handler, edge) { if (!isObject(object)) { throw new Error('Cannot watch: #{object}'); } var watching = true; var propertyWatchers = {}; var watchProperties = function (changes) { var properties = Object.keys(changes != null ? changes : object); for (var _i = 0; _i < properties.length; _i++) { var name = properties[_i]; (function (name) { if (watching) { propertyWatchers[name] != null ? propertyWatchers[name]() : void 0; delete propertyWatchers[name]; var value = object[name]; if (isObject(value)) { propertyWatchers[name] = watchInternal(value, function (patch) { if (watching) { var _ref = {}; _ref[name] = patch; handler(_ref); } }, edge); } } }(name)); } }; watchProperties(null); var unobserve = ion.observe(object, function (changes) { if (watching) { var patch = null; var changedProperties = {}; for (var _i2 = 0; _i2 < changes.length; _i2++) { var _ref2 = changes[_i2]; var name = _ref2.name; var oldValue = _ref2.oldValue; changedProperties[name] = true; if (!isPrivate(name)) { patch = patch != null ? patch : {}; var newValue = object[name]; var newDiff = diff(oldValue, newValue); if (newDiff !== void 0) { patch[name] = newDiff; } } } watchProperties(changedProperties); if (patch != null) { handler(patch); } } }, null, edge); return function () { watching = false; for (var key in propertyWatchers) { var unwatch = propertyWatchers[key]; unwatch(); } unobserve(); unobserve = null; }; }, increment = /[+-]\d+/, watchInternal = function (object, handler, edge) { global.watchInternalCount = global.watchInternalCount != null ? global.watchInternalCount : 0; global.watchInternalCount++; var active = false; var combinedPatch = void 0; var finalCallback = function () { handler(combinedPatch); active = false; combinedPatch = void 0; }; var delayedHandler = function (patch) { combinedPatch = combine(combinedPatch, patch); if (!active) { ion.nextCheck(finalCallback); active = true; } }; var unwatch = watchImmediate(object, delayedHandler, edge); return function () { unwatch(); global.watchInternalCount--; }; }; var canSetProperty = exports.canSetProperty = function (object, key) { return !(typeof object === 'function' && key === 'name'); }, merge = exports.merge = function (_target, _values, options, schema) { var values = _values; var target = _target; var deleteNull = (options != null ? options.deleteNull : void 0) != null ? options.deleteNull : true; var _delete = (options != null ? options.delete : void 0) != null ? options.delete : true; if ((schema != null ? schema.type : void 0) === 'integer' && increment.test(values)) { if (!deleteNull || typeof target === 'string' && increment.test(target)) { var total = parseInt(target != null ? target : 0) + parseInt(values.substring(1)); values = '' + (total > 0 ? '+' : '-') + Math.abs(total); } else { values = (typeof target === 'number' ? target : 0) + parseInt(values.substring(1)); } } if (Array.isArray(target) && (values != null ? values.length : void 0) === null) { target = {}; values = ion.clone(values, false); delete values.length; } if ((values != null ? values.constructor : void 0) !== Object) { if (Array.isArray(values)) { return values.slice(0); } else { return values; } } if (!isObject(target)) { if ((options != null ? options.factory : void 0) != null) { target = options.factory(values); } else { target = {}; } } var deletedValues = false; for (var key in values) { var value = values[key]; if (deleteNull && value === deleteValue) { deletedValues = true; if (_delete) { delete target[key]; } else { target[key] = void 0; } } else { var itemSchema = (schema != null ? schema.items : void 0) != null ? schema.items : schema != null ? schema.properties != null ? schema.properties[key] : void 0 : void 0; var newValue = merge(target[key], value, options, itemSchema); if (canSetProperty(target, key)) { target[key] = newValue; } } } if (deletedValues && Array.isArray(target)) { for (var i = target.length; i > 0; i--) { if (!(target[i - 1] != null)) { target.length = i - 1; } } } return target; }, patchNoDelete = exports.patchNoDelete = function (object, patch) { return merge(object, patch, { delete: false }); }, combine = exports.combine = function (patch1, patch2, schema) { return merge(patch1, patch2, { deleteNull: false }, schema); }, watch = exports.watch = function (object, handler, edge) { global.watchCount = global.watchCount != null ? global.watchCount : 0; global.watchCount++; var unwatch = watchInternal(object, handler, edge); return function () { unwatch(); global.watchCount--; }; }, diff = exports.diff = function (oldValue, newValue) { if (oldValue === newValue) { return void 0; } if (!(oldValue != null && newValue != null && typeof newValue === 'object' && typeof oldValue === 'object')) { return newValue != null ? newValue : null; } if (!Array.isArray(oldValue) && Array.isArray(newValue)) { return newValue; } if (Array.isArray(oldValue) && !Array.isArray(newValue)) { return ion.patch.combine(JSON.parse(JSON.stringify(newValue)), { length: null }); } var patch = void 0; for (var name in oldValue) { if (oldValue.hasOwnProperty(name)) { if (!newValue.hasOwnProperty(name)) { patch = patch != null ? patch : {}; patch[name] = null; } else { var propertyDiff = diff(oldValue[name], newValue[name]); if (propertyDiff !== void 0) { patch = patch != null ? patch : {}; patch[name] = propertyDiff; } } } } for (var name in newValue) { if (newValue.hasOwnProperty(name) && !oldValue.hasOwnProperty(name)) { patch = patch != null ? patch : {}; patch[name] = newValue[name]; } } if (Array.isArray(oldValue) && Array.isArray(newValue) && newValue.length < oldValue.length) { patch.length = newValue.length; for (var i = newValue.length; i < oldValue.length; i++) { delete patch[i]; } } return patch; }, isChange = exports.isChange = function (oldValue, newValue) { if (oldValue === newValue) { return false; } if (!(oldValue != null && newValue != null && typeof newValue === 'object' && typeof oldValue === 'object')) { return true; } if (Array.isArray(newValue) && JSON.stringify(oldValue) !== JSON.stringify(newValue)) { return true; } for (var name in newValue) { if (!oldValue.hasOwnProperty(name)) { if (!(newValue[name] != null)) { continue; } else { return true; } } if (isChange(oldValue[name], newValue[name])) { return true; } } return false; }, test = exports.test = function () { var equal = function (a, b) { return JSON.stringify(a) === JSON.stringify(b); }; return { merge: function () { if (!equal({ a: { b: 2, c: 3 }, d: 4 }, merge({ a: { b: 2 } }, { a: { c: 3 }, d: 4 }))) throw new Error('Assertion Failed: (equal({a:{b:2,c:3},d:4}, merge({a:{b:2}}, {a:{c:3},d:4})))'); if (!equal({ b: 2 }, merge(null, { b: 2 }))) throw new Error('Assertion Failed: (equal({b:2}, merge(null, {b:2})))'); if (!equal({ a: 1, b: 2 }, merge({ a: 1, b: 2, c: 3 }, { c: void 0 }))) throw new Error('Assertion Failed: (equal({a:1,b:2}, merge({a:1,b:2,c:3}, {c:undefined})))'); var double = function (x) { return x * 2; }; if (!equal({ a: double }, merge({}, { a: double }))) throw new Error('Assertion Failed: (equal({a:double}, merge({},{a:double})))'); if (!equal({ a: [] }, merge({ a: [ 1, 2 ] }, { a: [] }))) throw new Error('Assertion Failed: (equal({a:[]}, merge({a:[1,2]}, {a:[]})))'); if (!('+2' === merge('+1', '+1', null, { type: 'integer' }))) throw new Error('Assertion Failed: ("+2" is merge("+1", "+1", null, {type:\'integer\'}))'); if (!equal([1], merge([ 1, 2 ], { 1: null }))) throw new Error('Assertion Failed: (equal([1], merge([1,2], {1:null})))'); if (!(merge([ 1, 2 ], { 1: null }).length === 1)) throw new Error('Assertion Failed: (merge([1,2], {1:null}).length is 1)'); if (!(merge({ foo: [ 1, 2 ] }, { foo: { 1: null } }).foo.length === 1)) throw new Error('Assertion Failed: (merge({foo:[1,2]}, {foo:{1:null}}).foo.length is 1)'); if (!equal([ 1, void 0 ], merge([ 1, 2 ], { 1: void 0 }))) throw new Error('Assertion Failed: (equal([1, undefined], merge([1,2], {1:undefined})))'); }, isChange: function () { if (!isChange({ a: 1 }, null)) throw new Error('Assertion Failed: (isChange({a:1}, null))'); if (!!isChange(null, null)) throw new Error('Assertion Failed: (not isChange(null, null))'); if (!isChange(void 0, null)) throw new Error('Assertion Failed: (isChange(undefined, null))'); if (!isChange(null, void 0)) throw new Error('Assertion Failed: (isChange(null, undefined))'); if (!!isChange({ a: 1 }, { a: 1 })) throw new Error('Assertion Failed: (not isChange({a:1}, {a:1}))'); if (!!isChange({ a: { b: 2, c: 3 } }, { a: { b: 2 } })) throw new Error('Assertion Failed: (not isChange({a:{b:2,c:3}}, {a:{b:2}}))'); if (!isChange({ a: { b: 2 } }, { a: { b: 3 } })) throw new Error('Assertion Failed: (isChange({a:{b:2}}, {a:{b:3}}))'); if (!!isChange({ a: 1 }, { b: null })) throw new Error('Assertion Failed: (not isChange({a:1}, {b:null}))'); if (!isChange({ a: [ 1, 2 ] }, { a: [] })) throw new Error('Assertion Failed: (isChange({a:[1,2]}, {a:[]}))'); }, diff: function () { if (!equal({ b: 2 }, diff({ a: 1 }, { a: 1, b: 2 }))) throw new Error('Assertion Failed: (equal({b:2}, diff({a:1}, {a:1,b:2})))'); if (!equal({ a: { b: 3, c: null } }, diff({ a: { b: 2, c: 4 } }, { a: { b: 3 } }))) throw new Error('Assertion Failed: (equal({a:{b:3,c:null}}, diff({a:{b:2,c:4}}, {a:{b:3}})))'); if (!equal({ a: 1 }, diff(null, { a: 1 }))) throw new Error('Assertion Failed: (equal({a:1}, diff(null, {a:1})))'); if (!equal({ c: { d: { f: 4 } } }, diff({ a: 1, b: 2, c: { d: { e: 1, f: 2 } } }, { a: 1, b: 2, c: { d: { e: 1, f: 4 } } }))) throw new Error('Assertion Failed: (equal({c:{d:{f:4}}}, diff({a:1,b:2,c:{d:{e:1,f:2}}}, {a:1,b:2,c:{d:{e:1,f:4}}})))'); if (!equal(null, diff({ a: 1 }, void 0))) throw new Error('Assertion Failed: (equal(null, diff({a:1}, undefined)))'); if (!equal(null, diff({ a: 1 }, null))) throw new Error('Assertion Failed: (equal(null, diff({a:1}, null)))'); if (!equal(void 0, diff({ a: { b: 2 } }, { a: { b: 2 } }))) throw new Error('Assertion Failed: (equal(undefined, diff({a:{b:2}}, {a:{b:2}})))'); if (!equal(diff([ 1, 2, 3 ], [ 3, 2 ]), { '0': 3, length: 2 })) throw new Error('Assertion Failed: ((equal(diff([1,2,3], [3,2]), { \'0\': 3, length: 2 })))'); if (!equal(diff([], {}), { length: null })) throw new Error('Assertion Failed: (equal(diff([], {}), {length:null}))'); if (!equal(diff({}, []), [])) throw new Error('Assertion Failed: (equal(diff({}, []), []))'); var start = [ 1, 2, 3 ]; var delta = diff(start, { foo: 'a' }); var result = merge(start, delta); if (!equal(result, { foo: 'a' })) throw new Error('Assertion Failed: (equal(result, {foo:"a"}))'); }, mergeActuallySetsValuesEvenWhenValueIsntChanged: function () { var Point = ion.defineClass({ name: 'Point', properties: { x: 0, y: 0 } }); var Point = Point; var a = new Point({}); if (!!a.hasOwnProperty('x')) throw new Error('Assertion Failed: (not a.hasOwnProperty(\'x\'))'); merge(a, { x: 0 }); if (!a.hasOwnProperty('x')) throw new Error('Assertion Failed: (a.hasOwnProperty(\'x\'))'); }, observe: function (done) { var before = global.watchCount != null ? global.watchCount : 0; var source = { name: 'Kris', age: 41, children: { Sadera: { grandchildren: { One: 1, Two: 2 } }, Orion: [], Third: {}, Fifth: { alpha: 1 } } }; var target = ion.clone(source, true); var unwatch = watch(source, function (patch) { target = merge(target, patch); if (equal(source, target)) { unwatch(); var after = global.watchCount; if (before !== after) { done('Memory leak in watch: before = ' + before + ', after = ' + after); } else { done(); } } }); ion.patch.combine(source, { name: 'Fred', children: { Orion: { a: 1, b: 2, c: 12 }, Sadera: { grandchildren: { three: 3 } }, Fourth: { Something: { One: 1, Two: 2 } } } }); source.children.Fifth = { beta: 2 }; delete source.children.Third; ion.sync(); } }; }(); } if (typeof require === 'function') { if (require.register) require.register('ion/mergePatch',_ion_mergePatch_); else _ion_mergePatch_.call(this, module, exports, require); } else { _ion_mergePatch_.call(this); } }).call(this)