Comparing version 1.0.1 to 2.0.0
12
API.md
@@ -44,4 +44,2 @@ # crio API | ||
* Retrieve value in deeply nested object based on array of keys | ||
* log {string} *title, optional* | ||
* Convenience method to display the standard JavaScript array with values in console | ||
* merge {array[, array2, ..., arrayN]} *objects*, returns {crio} | ||
@@ -74,7 +72,2 @@ * Shallow merge any number of items into existing crio | ||
* Determines whether array is deeply equal in value to another by comparing hashCodes | ||
* filter {function} *callback*, returns {crio} | ||
* Loops over each item in the map, passing the value, key, and original object as parameters to callback | ||
* If value returned in the callback iteration is false, then that key is removed from the object | ||
* forEach {function} *callback* | ||
* Loops over each item in the map, passing the value, key, and original object as parameters to callback | ||
* get {number|string} *key*, returns {any} | ||
@@ -84,7 +77,2 @@ * Retrieve value at key | ||
* Retrieve value in deeply nested object based on array of keys | ||
* log {string} *title, optional* | ||
* Convenience method to display the standard JavaScript object with values in console | ||
* map {function} *callback*, returns {crio} | ||
* Loops over each item in the map, passing the value, key, and original object as parameters to callback | ||
* Value returned in each iteration of callback will be assigned to that iteration's key | ||
* merge {object[, object2, ..., objectN]} *objects*, returns {crio} | ||
@@ -91,0 +79,0 @@ * Shallow merge any number of items into existing crio |
# crio changelog | ||
#### 2.0.0 | ||
* Complete rewrite for performance and sustainability | ||
* Full code coverage with AVA | ||
#### 1.0.1 | ||
@@ -4,0 +8,0 @@ * Improve bug in .equals() to be recursive |
1612
lib/index.js
'use strict'; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.CrioObject = exports.CrioArray = exports.isCrio = exports.getRealValue = exports.assignOnDeepMatch = undefined; | ||
var _crioIdentifier = require('./crioIdentifier'); | ||
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 _crioIdentifier2 = _interopRequireDefault(_crioIdentifier); | ||
require('core-js/fn/symbol'); | ||
var _utils = require('./utils'); | ||
require('core-js/fn/object/entries'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
require('core-js/fn/object/keys'); | ||
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; } | ||
require('core-js/fn/object/values'); | ||
var _utils = require('./utils'); | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
var immutableArrayMethods = { | ||
onlyApplyMethods: ['filter', 'slice'], | ||
fullCrio: ['join', 'map', 'reduce', 'reduceRight'] | ||
}; | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var ASSIGN = Object.assign; | ||
var CREATE = Object.create; | ||
var DEFINE_PROPERTY = Object.defineProperty; | ||
var FREEZE = Object.freeze; | ||
var GET_OWN_PROPERTY_DESCRIPTOR = Object.getOwnPropertyDescriptor; | ||
var GET_OWN_PROPERTY_NAMES = Object.getOwnPropertyNames; | ||
var KEYS = Object.keys; | ||
var ARRAY_PROTOTYPE = Array.prototype; | ||
var OBJECT_ENTRIES = Object.entries; | ||
var OBJECT_FREEZE = Object.freeze; | ||
var OBJECT_KEYS = Object.keys; | ||
var OBJECT_OWN_PROPERTY_NAMES = Object.getOwnPropertyNames; | ||
var OBJECT_PROTOTYPE = Object.prototype; | ||
var OBJECT_VALUES = Object.values; | ||
var NATIVE_KEYS = ['$$hashCode', '$$type', 'length']; | ||
/** | ||
* is object a CrioArray or CrioObject | ||
* | ||
* @param {any} object | ||
* @returns {boolean} | ||
*/ | ||
var isCrio = function isCrio(object) { | ||
return !!object[_crioIdentifier2.default]; | ||
return object instanceof CrioArray || object instanceof CrioObject; | ||
}; | ||
var allAdditionalMethods = { | ||
delete: function _delete(key) { | ||
if ((0, _utils.isArray)(this)) { | ||
return (0, _utils.getRestOfObject)(this, key); | ||
} | ||
/** | ||
* if the value is not a crio and is an array or object, convert | ||
* it to crio and return it, else just return it | ||
* | ||
* @param {any} value | ||
* @returns {any} | ||
*/ | ||
var getRealValue = function getRealValue(value) { | ||
if (!isCrio(value)) { | ||
if ((0, _utils.isArray)(value)) { | ||
return new CrioArray(value); | ||
} | ||
return returnFrozenWithMethods(_extends({}, (0, _utils.getRestOfObject)(this, key)), false); | ||
}, | ||
deleteIn: function deleteIn(keys) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
return this; | ||
if ((0, _utils.isObject)(value)) { | ||
return new CrioObject(value); | ||
} | ||
} | ||
var lastKeyIndex = keys.length - 1; | ||
return value; | ||
}; | ||
var currentObject = this.thaw(), | ||
referenceToCurrentObject = currentObject; | ||
/** | ||
* on deep match via setIn or mergeIn, perform assignment | ||
* | ||
* @param {object} object | ||
* @param {array<string>} keys | ||
* @param {any} value | ||
* @param {boolean} isMerge=false | ||
* @returns {CrioArray|CrioObject} | ||
*/ | ||
var assignOnDeepMatch = function assignOnDeepMatch(object, keys, value) { | ||
var isMerge = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3]; | ||
for (var keyIndex = 0, length = lastKeyIndex + 1; keyIndex < length; keyIndex++) { | ||
var key = keys[keyIndex]; | ||
var currentValue = currentObject[key]; | ||
var length = keys.length; | ||
var lastIndex = length - 1; | ||
var FinalCrio = (0, _utils.isArray)(object) ? CrioArray : CrioObject; | ||
if (keyIndex === lastKeyIndex) { | ||
delete currentObject[key]; | ||
break; | ||
} | ||
var currentObject = object.thaw(), | ||
referenceToCurrentObject = currentObject, | ||
Crio = void 0; | ||
if (!(0, _utils.isArray)(currentValue) && !(0, _utils.isObject)(currentValue)) { | ||
return this; | ||
} | ||
for (var index = 0; index < length; index++) { | ||
var key = keys[index] + ''; | ||
var currentValue = currentObject[key]; | ||
currentObject = currentObject[key]; | ||
} | ||
if (!(0, _utils.isArray)(currentValue) && !(0, _utils.isObject)(currentValue)) { | ||
currentObject[key] = {}; | ||
} | ||
return crio(referenceToCurrentObject); | ||
}, | ||
equals: function equals(object) { | ||
return (0, _utils.isEqual)(this, object); | ||
}, | ||
get: function get(key) { | ||
return this[key]; | ||
}, | ||
getIn: function getIn(keys) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
return this; | ||
if (index === lastIndex) { | ||
Crio = (0, _utils.isArray)(currentObject) ? CrioArray : CrioObject; | ||
currentObject[key] = isMerge ? Crio.prototype.merge.apply(currentObject[key], value) : value; | ||
} else { | ||
currentObject = currentObject[key]; | ||
} | ||
} | ||
var lastKeyIndex = keys.length - 1; | ||
var crioedObject = new FinalCrio(referenceToCurrentObject); | ||
var currentObject = this; | ||
return (0, _utils.returnObjectOnlyIfNew)(undefined, crioedObject); | ||
}; | ||
for (var keyIndex = 0, length = lastKeyIndex + 1; keyIndex < length; keyIndex++) { | ||
var key = keys[keyIndex]; | ||
var CrioArray = function () { | ||
function CrioArray(array) { | ||
_classCallCheck(this, CrioArray); | ||
if ((0, _utils.isUndefined)(currentObject[key]) || keyIndex === lastKeyIndex) { | ||
return currentObject[key]; | ||
} | ||
if (isCrio(array)) { | ||
return array; | ||
} | ||
currentObject = currentObject[key]; | ||
} | ||
}, | ||
log: function log(title) { | ||
var thawed = this.thaw(); | ||
var length = array.length; | ||
if (title) { | ||
console.log(title, thawed); | ||
} else { | ||
console.log(thawed); | ||
} | ||
for (var index = 0; index < length; index++) { | ||
var value = getRealValue(array[index]); | ||
return this; | ||
}, | ||
merge: function merge() { | ||
var isThisArray = (0, _utils.isArray)(this); | ||
(0, _utils.setReadOnly)(this, index, value, array.propertyIsEnumerable(index)); | ||
} | ||
var shallowClone = isThisArray ? [].concat(_toConsumableArray(this)) : _extends({}, this); | ||
(0, _utils.setNonEnumerable)(this, 'length', length); | ||
for (var _len = arguments.length, objects = Array(_len), _key = 0; _key < _len; _key++) { | ||
objects[_key] = arguments[_key]; | ||
return OBJECT_FREEZE(this); | ||
} | ||
objects.forEach(function (object) { | ||
for (var key in object) { | ||
shallowClone[key] = crio(object[key]); | ||
} | ||
}); | ||
/** | ||
* return unique hash of this values | ||
* | ||
* @return {number} | ||
*/ | ||
return returnFrozenWithMethods(shallowClone, isThisArray); | ||
}, | ||
mergeIn: function mergeIn(keys) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
return this; | ||
} | ||
var lastKeyIndex = keys.length - 1; | ||
_createClass(CrioArray, [{ | ||
key: 'concat', | ||
var currentObject = this.thaw(), | ||
referenceToCurrentObject = currentObject; | ||
for (var _len2 = arguments.length, objects = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { | ||
objects[_key2 - 1] = arguments[_key2]; | ||
} | ||
/** | ||
* based on items passed, combine with this to create new CrioArray | ||
* | ||
* @param {array<any>} items | ||
* @returns {CrioArray} | ||
*/ | ||
value: function concat() { | ||
for (var _len = arguments.length, items = Array(_len), _key = 0; _key < _len; _key++) { | ||
items[_key] = arguments[_key]; | ||
} | ||
for (var keyIndex = 0, length = lastKeyIndex + 1; keyIndex < length; keyIndex++) { | ||
var key = keys[keyIndex]; | ||
var currentValue = currentObject[key]; | ||
if (!items.length) { | ||
return this; | ||
} | ||
if (!(0, _utils.isArray)(currentValue) && !(0, _utils.isObject)(currentValue)) { | ||
currentObject[key] = {}; | ||
} | ||
return new CrioArray([].concat(_toConsumableArray(this), items)); | ||
} | ||
if (keyIndex === lastKeyIndex) { | ||
currentObject[key] = this.merge.apply(currentObject[key], objects); | ||
break; | ||
} | ||
/** | ||
* based on arguments passed, return new CrioArray with copyWithin applied | ||
* | ||
* @param {array<any>} args | ||
* @returns {CrioArray} | ||
*/ | ||
currentObject = currentObject[key]; | ||
} | ||
}, { | ||
key: 'copyWithin', | ||
value: function copyWithin() { | ||
var _thaw; | ||
return crio(referenceToCurrentObject, (0, _utils.isArray)(this)); | ||
}, | ||
mutate: function mutate(mutateMapFunction) { | ||
var result = mutateMapFunction.call(this, this.thaw()); | ||
var copiedClone = (_thaw = this.thaw()).copyWithin.apply(_thaw, arguments); | ||
var crioedClone = new CrioArray(copiedClone); | ||
return crio(result); | ||
}, | ||
set: function set(key, value) { | ||
if (!key) { | ||
return this; | ||
} | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedClone); | ||
} | ||
var isThisArray = (0, _utils.isArray)(this); | ||
/** | ||
* returns an oterable array of [index, value] pairs | ||
* | ||
* @returns {array<array>} | ||
*/ | ||
if (isThisArray) { | ||
return this.map(function (item, itemIndex) { | ||
if (itemIndex === key) { | ||
return crio(value); | ||
}, { | ||
key: 'entries', | ||
value: function entries() { | ||
return OBJECT_ENTRIES(this.thaw()); | ||
} | ||
return item; | ||
}); | ||
} | ||
/** | ||
* is the object passed equal in value to this | ||
* | ||
* @param {any} object | ||
* @returns {boolean} | ||
*/ | ||
return returnFrozenWithMethods(_extends({}, (0, _utils.getRestOfObject)(this, key), _defineProperty({}, key, crio(value))), isThisArray); | ||
}, | ||
setIn: function setIn(keys, value) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
return this; | ||
} | ||
}, { | ||
key: 'equals', | ||
value: function equals(object) { | ||
if (!isCrio(object)) { | ||
return false; | ||
} | ||
var lastKeyIndex = keys.length - 1; | ||
return this.$$hashCode === object.$$hashCode; | ||
} | ||
var currentObject = this.thaw(), | ||
referenceToCurrentObject = currentObject; | ||
/** | ||
* does the function applied to every value in this return truthy | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
* @returns {boolean} | ||
*/ | ||
for (var keyIndex = 0, length = lastKeyIndex + 1; keyIndex < length; keyIndex++) { | ||
var key = keys[keyIndex]; | ||
var currentValue = currentObject[key]; | ||
}, { | ||
key: 'every', | ||
value: function every(fn) { | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
if (!(0, _utils.isArray)(currentValue) && !(0, _utils.isObject)(currentValue)) { | ||
currentObject[key] = {}; | ||
} | ||
for (var index = 0, length = this.length; index < length; index++) { | ||
if (!fn.call(thisArg, this[index], index, this)) { | ||
return false; | ||
} | ||
} | ||
if (keyIndex === lastKeyIndex) { | ||
currentObject[key] = crio(value); | ||
break; | ||
} | ||
return true; | ||
} | ||
currentObject = currentObject[key]; | ||
} | ||
/** | ||
* fill this based on arguments and return new CrioArray | ||
* | ||
* @param {array<any>} args | ||
* @returns {CrioArray} | ||
*/ | ||
return crio(referenceToCurrentObject); | ||
}, | ||
thaw: function thaw() { | ||
return (0, _utils.getMutableObject)(this); | ||
} | ||
}; | ||
var arrayAdditionalMethods = { | ||
concat: function concat() { | ||
for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
args[_key3] = arguments[_key3]; | ||
} | ||
}, { | ||
key: 'fill', | ||
value: function fill() { | ||
var clone = this.thaw(); | ||
args.forEach(function (arg, argIndex) { | ||
args[argIndex] = crio(arg); | ||
}); | ||
clone.fill.apply(clone, arguments); | ||
return returnFrozenWithMethods(Array.prototype.concat.apply(this, args), true); | ||
}, | ||
copyWithin: function copyWithin(targetIndex, startIndex) { | ||
var endIndex = arguments.length <= 2 || arguments[2] === undefined ? this.length : arguments[2]; | ||
return new CrioArray(clone); | ||
} | ||
targetIndex = (0, _utils.coerceToInteger)(targetIndex); | ||
startIndex = (0, _utils.coerceToInteger)(startIndex); | ||
endIndex = (0, _utils.coerceToInteger)(endIndex); | ||
/** | ||
* based on return values of fn being truthy, return a new reduced CrioArray | ||
* from this | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
* @returns {CrioArray} | ||
*/ | ||
if (startIndex < 0) { | ||
startIndex = this.length + startIndex; | ||
} | ||
}, { | ||
key: 'filter', | ||
value: function filter(fn) { | ||
var _this = this; | ||
if (endIndex < 0) { | ||
endIndex = this.length + endIndex; | ||
} | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
var copyValues = this.slice(startIndex, endIndex); | ||
var filteredArray = OBJECT_KEYS(this).reduce(function (array, key) { | ||
var result = fn.call(thisArg, _this[key], +key, _this); | ||
var copyIndex = 0; | ||
if (result) { | ||
return array.concat(_this[key]); | ||
} | ||
return this.map(function (item, itemIndex) { | ||
if (copyIndex === copyValues.length || itemIndex >= startIndex && itemIndex < endIndex) { | ||
return item; | ||
} | ||
return array; | ||
}, []); | ||
var crioedArray = new CrioArray(filteredArray); | ||
copyIndex++; | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedArray); | ||
} | ||
return copyValues[copyIndex - 1]; | ||
}); | ||
}, | ||
fill: function fill(value) { | ||
var startIndex = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1]; | ||
var endIndex = arguments.length <= 2 || arguments[2] === undefined ? this.length : arguments[2]; | ||
/** | ||
* find a specific value in the CrioArray and return it, else return undefined | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
* @returns {any} | ||
*/ | ||
startIndex = (0, _utils.coerceToInteger)(startIndex); | ||
endIndex = (0, _utils.coerceToInteger)(endIndex); | ||
}, { | ||
key: 'find', | ||
value: function find(fn) { | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
value = crio(value); | ||
for (var index = 0; index < this.length; index++) { | ||
var value = this[index]; | ||
if (startIndex < 0) { | ||
startIndex = this.length + startIndex; | ||
} | ||
if (fn.call(thisArg, value, index, this)) { | ||
return value; | ||
} | ||
} | ||
if (endIndex < 0) { | ||
endIndex = this.length + endIndex; | ||
} | ||
return undefined; | ||
} | ||
var tempArray = []; | ||
/** | ||
* find a specific value in the CrioArray and return its index, else return -1 | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
* @returns {number} | ||
*/ | ||
this.forEach(function (item, itemIndex) { | ||
if (itemIndex >= startIndex && itemIndex < endIndex) { | ||
tempArray[itemIndex] = value; | ||
} else { | ||
tempArray[itemIndex] = item; | ||
} | ||
}); | ||
}, { | ||
key: 'findIndex', | ||
value: function findIndex(fn) { | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
return returnFrozenWithMethods(tempArray, true); | ||
}, | ||
forEach: function forEach(forEachFunction) { | ||
for (var index = 0, length = this.length; index < length; index++) { | ||
var result = forEachFunction.call(this, this[index], index, this); | ||
for (var index = 0; index < this.length; index++) { | ||
if (fn.call(thisArg, this[index], index, this)) { | ||
return index; | ||
} | ||
} | ||
if (result === false) { | ||
return this; | ||
} | ||
} | ||
}, | ||
pop: function pop() { | ||
var tempArray = [].concat(_toConsumableArray(this.slice(0, this.length - 1))); | ||
return -1; | ||
} | ||
return returnFrozenWithMethods(tempArray, true); | ||
}, | ||
push: function push() { | ||
var tempArray = [].concat(_toConsumableArray(this)), | ||
length = this.length; | ||
/** | ||
* iterate over this and execute fn for each value | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
*/ | ||
for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { | ||
args[_key4] = arguments[_key4]; | ||
} | ||
}, { | ||
key: 'forEach', | ||
value: function forEach(fn) { | ||
var _this2 = this; | ||
args.forEach(function (arg) { | ||
(0, _utils.setImmutable)(tempArray, length, crio(arg)); | ||
length++; | ||
}); | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
return returnFrozenWithMethods(tempArray, true); | ||
}, | ||
reverse: function reverse() { | ||
var tempArray = [].concat(_toConsumableArray(this)).reverse(); | ||
this.keys().forEach(function (key) { | ||
fn.call(thisArg, _this2[key], +key, _this2); | ||
}); | ||
} | ||
return returnFrozenWithMethods(tempArray, true); | ||
}, | ||
shift: function shift() { | ||
var tempArray = [].concat(_toConsumableArray(this.slice(1, this.length))); | ||
/** | ||
* retrieve the value at index from this | ||
* | ||
* @param {number} index | ||
* @returns {any} | ||
*/ | ||
return returnFrozenWithMethods(tempArray, true); | ||
}, | ||
sort: function sort(sortFunction) { | ||
var tempArray = (0, _utils.getMutableObject)(this); | ||
}, { | ||
key: 'get', | ||
value: function get(index) { | ||
return this[index]; | ||
} | ||
tempArray.sort(sortFunction); | ||
/** | ||
* return value at nested point based on keys in this | ||
* | ||
* @param {array<string|number>} keys | ||
* @return {any} | ||
*/ | ||
return crioArray(tempArray); | ||
}, | ||
splice: function splice(startIndex) { | ||
for (var _len5 = arguments.length, items = Array(_len5 > 2 ? _len5 - 2 : 0), _key5 = 2; _key5 < _len5; _key5++) { | ||
items[_key5 - 2] = arguments[_key5]; | ||
} | ||
}, { | ||
key: 'getIn', | ||
value: function getIn(keys) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
throw new Error('Must provide keys as an array, such as ["foo", "bar"].'); | ||
} | ||
var deleteCount = arguments.length <= 1 || arguments[1] === undefined ? 1 : arguments[1]; | ||
var length = keys.length; | ||
var lastIndex = length - 1; | ||
startIndex = (0, _utils.coerceToInteger)(startIndex); | ||
deleteCount = (0, _utils.coerceToInteger)(deleteCount); | ||
var currentObject = this; | ||
items.forEach(function (item, itemIndex) { | ||
items[itemIndex] = crio(item); | ||
}); | ||
for (var index = 0; index < length; index++) { | ||
var key = keys[index]; | ||
var tempArray = [].concat(_toConsumableArray(this.slice(0, startIndex)), items, _toConsumableArray(this.slice(startIndex + deleteCount, this.length))); | ||
if ((0, _utils.isUndefined)(currentObject[key]) || index === lastIndex) { | ||
return currentObject[key]; | ||
} | ||
return returnFrozenWithMethods(tempArray, true); | ||
}, | ||
unshift: function unshift() { | ||
for (var _len6 = arguments.length, args = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { | ||
args[_key6] = arguments[_key6]; | ||
} | ||
currentObject = currentObject[key]; | ||
} | ||
} | ||
}, { | ||
key: 'includes', | ||
args.forEach(function (arg, argIndex) { | ||
args[argIndex] = crio(arg); | ||
}); | ||
var tempArray = [].concat(args, _toConsumableArray(this)); | ||
/** | ||
* does this have a value of item contained in it | ||
* | ||
* @param {any} item | ||
* @returns {boolean} | ||
*/ | ||
value: function includes(item) { | ||
return this.indexOf(item) !== -1; | ||
} | ||
return returnFrozenWithMethods(tempArray, true); | ||
} | ||
}; | ||
var objectAdditionalMethods = { | ||
filter: function filter(filterFunction) { | ||
var thisProperties = GET_OWN_PROPERTY_NAMES(this); | ||
/** | ||
* what is the index of item in this (if not found, defaults to -1) | ||
* | ||
* @param {any} item | ||
* @returns {number} | ||
*/ | ||
var newObject = addObjectPrototypeMethods({}); | ||
}, { | ||
key: 'indexOf', | ||
value: function indexOf(item) { | ||
return ARRAY_PROTOTYPE.indexOf.call(this, item); | ||
} | ||
for (var index = 0, length = thisProperties.length; index < length; index++) { | ||
var property = thisProperties[index]; | ||
var descriptor = GET_OWN_PROPERTY_DESCRIPTOR(this, property); | ||
var result = filterFunction.call(this, this[property], property, this); | ||
/** | ||
* joins this into string based on separator delimiting between values | ||
* | ||
* @param {string} separator | ||
* @returns {string} | ||
*/ | ||
if (result !== false && property !== _crioIdentifier2.default) { | ||
(0, _utils.setImmutable)(newObject, property, this[property], descriptor); | ||
} | ||
} | ||
}, { | ||
key: 'join', | ||
value: function join() { | ||
var _this3 = this; | ||
return FREEZE(newObject); | ||
}, | ||
forEach: function forEach(forEachFunction) { | ||
var thisProperties = KEYS(this); | ||
var separator = arguments.length <= 0 || arguments[0] === undefined ? ',' : arguments[0]; | ||
for (var index = 0, length = thisProperties.length; index < length; index++) { | ||
var property = thisProperties[index]; | ||
var result = forEachFunction.call(this, this[property], property, this); | ||
var string = ''; | ||
if (result === false) { | ||
break; | ||
} | ||
} | ||
this.keys().forEach(function (key, keyIndex) { | ||
if (keyIndex !== 0) { | ||
string += separator; | ||
} | ||
return this; | ||
}, | ||
map: function map(mapFunction) { | ||
var thisProperties = GET_OWN_PROPERTY_NAMES(this); | ||
string += _this3[key].toString(); | ||
}); | ||
var newObject = addObjectPrototypeMethods({}); | ||
return string; | ||
} | ||
for (var index = 0, length = thisProperties.length; index < length; index++) { | ||
var property = thisProperties[index]; | ||
var descriptor = GET_OWN_PROPERTY_DESCRIPTOR(this, property); | ||
/** | ||
* returns keys of array (list of indices) | ||
* | ||
* @returns {array<string>} | ||
*/ | ||
if (property !== _crioIdentifier2.default) { | ||
(0, _utils.setImmutable)(newObject, property, mapFunction.call(this, this[property], property, this), descriptor); | ||
} | ||
} | ||
}, { | ||
key: 'keys', | ||
value: function keys() { | ||
return OBJECT_KEYS(this); | ||
} | ||
return FREEZE(newObject); | ||
} | ||
}; | ||
/** | ||
* last index of item in this | ||
* | ||
* @param {any} item | ||
* @returns {number} | ||
*/ | ||
var arrayMethods = _extends({}, allAdditionalMethods, arrayAdditionalMethods); | ||
}, { | ||
key: 'lastIndexOf', | ||
value: function lastIndexOf(item) { | ||
return ARRAY_PROTOTYPE.lastIndexOf.call(this, item); | ||
} | ||
immutableArrayMethods.onlyApplyMethods.forEach(function (method) { | ||
arrayMethods[method] = function () { | ||
for (var _len7 = arguments.length, args = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { | ||
args[_key7] = arguments[_key7]; | ||
} | ||
/** | ||
* iterate over this and assign values returned from calling | ||
* fn to a new CrioArray | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
* @returns {CrioArray} | ||
*/ | ||
args.forEach(function (arg, argIndex) { | ||
args[argIndex] = crio(arg); | ||
}); | ||
}, { | ||
key: 'map', | ||
value: function map(fn) { | ||
var _this4 = this; | ||
return returnFrozenWithMethods(Array.prototype[method].apply(this, args), true); | ||
}; | ||
}); | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
immutableArrayMethods.fullCrio.forEach(function (method) { | ||
arrayMethods[method] = function () { | ||
for (var _len8 = arguments.length, args = Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { | ||
args[_key8] = arguments[_key8]; | ||
} | ||
var mappedArray = this.keys().map(function (key) { | ||
return fn.call(thisArg, _this4[key], +key, _this4); | ||
}); | ||
var crioedArray = new CrioArray(mappedArray); | ||
args.forEach(function (arg, argIndex) { | ||
args[argIndex] = crio(arg); | ||
}); | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedArray); | ||
} | ||
return crio(Array.prototype[method].apply(this, args)); | ||
}; | ||
}); | ||
/** | ||
* shallowly merge each object into this | ||
* | ||
* @param {array<any>} objects | ||
* @returns {CrioArray} | ||
*/ | ||
var objectMethods = _extends({}, Object.prototype, allAdditionalMethods, objectAdditionalMethods); | ||
}, { | ||
key: 'merge', | ||
value: function merge() { | ||
var clone = isCrio(this) ? this.thaw() : this; | ||
var addArrayPrototypeMethods = function addArrayPrototypeMethods(array) { | ||
if (isCrio(array)) { | ||
return array; | ||
} | ||
for (var _len2 = arguments.length, objects = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
objects[_key2] = arguments[_key2]; | ||
} | ||
var newArray = ASSIGN([], array, arrayMethods); | ||
objects.forEach(function (object) { | ||
clone = clone.map(function (key, index) { | ||
return object[index] || clone[index]; | ||
}); | ||
}); | ||
setCrioIdentifier(newArray); | ||
var crioedArray = new CrioArray(clone); | ||
return newArray; | ||
}; | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedArray); | ||
} | ||
var addObjectPrototypeMethods = function addObjectPrototypeMethods(object) { | ||
if (isCrio(object)) { | ||
return object; | ||
} | ||
/** | ||
* deeply merge all objects into location specified by keys | ||
* | ||
* @param {array<string|number>} keys | ||
* @param {array<any>} objects | ||
* @returns {CrioArray} | ||
*/ | ||
var newObject = CREATE(objectMethods); | ||
}, { | ||
key: 'mergeIn', | ||
value: function mergeIn(keys) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
throw new Error('Must provide keys as an array, such as ["foo", "bar"].'); | ||
} | ||
setCrioIdentifier(newObject); | ||
for (var _len3 = arguments.length, objects = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { | ||
objects[_key3 - 1] = arguments[_key3]; | ||
} | ||
GET_OWN_PROPERTY_NAMES(object).forEach(function (property) { | ||
var descriptor = GET_OWN_PROPERTY_DESCRIPTOR(object, property); | ||
if (!objects.length) { | ||
return this; | ||
} | ||
DEFINE_PROPERTY(newObject, property, descriptor); | ||
}); | ||
return assignOnDeepMatch(this, keys, objects, true); | ||
} | ||
return newObject; | ||
}; | ||
/** | ||
* convenience function to work with mutable version of this, | ||
* in case many modifications need to be made and performance | ||
* is paramount | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
* @returns {any} | ||
*/ | ||
var returnFrozenWithMethods = function returnFrozenWithMethods(object, isObjectArray) { | ||
var addMethods = isObjectArray ? addArrayPrototypeMethods : addObjectPrototypeMethods; | ||
}, { | ||
key: 'mutate', | ||
value: function mutate(fn) { | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
return FREEZE(addMethods(object)); | ||
}; | ||
var result = fn.call(thisArg, this.thaw(), this); | ||
var crioedValue = getRealValue(result); | ||
var setCrioIdentifier = function setCrioIdentifier(object) { | ||
DEFINE_PROPERTY(object, _crioIdentifier2.default, { | ||
configurable: false, | ||
enumerable: false, | ||
value: true, | ||
writable: true | ||
}); | ||
}; | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedValue); | ||
} | ||
var crioArray = function crioArray(array) { | ||
var crioedArray = addArrayPrototypeMethods([]); | ||
/** | ||
* return array with last item removed | ||
* | ||
* @returns {CrioArray} | ||
*/ | ||
array.forEach(function (item, itemIndex) { | ||
var itemValue = item; | ||
}, { | ||
key: 'pop', | ||
value: function pop() { | ||
return this.slice(0, this.length - 1); | ||
} | ||
if (!isCrio(item)) { | ||
itemValue = crio(item); | ||
} | ||
/** | ||
* return new CrioArray with items pushed to it | ||
* | ||
* @param {array<any>} items | ||
* @returns {CrioArray} | ||
*/ | ||
(0, _utils.setImmutable)(crioedArray, itemIndex, itemValue); | ||
}); | ||
}, { | ||
key: 'push', | ||
value: function push() { | ||
return this.concat.apply(this, arguments); | ||
} | ||
setCrioIdentifier(crioedArray); | ||
/** | ||
* based on fn, reduce the CrioArray and return either the crio of the reduced object | ||
* or the object itself | ||
* | ||
* @param {function} fn | ||
* @param {any} object | ||
* @param {any} thisArg | ||
* @returns {any} | ||
*/ | ||
return FREEZE(crioedArray); | ||
}; | ||
}, { | ||
key: 'reduce', | ||
value: function reduce(fn, object) { | ||
var thisArg = arguments.length <= 2 || arguments[2] === undefined ? this : arguments[2]; | ||
var crioObject = function crioObject(object) { | ||
var crioedObject = CREATE(objectMethods); | ||
var reduction = ARRAY_PROTOTYPE.reduce.call(this, fn, object, thisArg); | ||
var crioedReduction = getRealValue(reduction); | ||
GET_OWN_PROPERTY_NAMES(object).forEach(function (property) { | ||
var itemValue = object[property]; | ||
return !crioedReduction || !crioedReduction.$$hashCode ? crioedReduction : (0, _utils.returnObjectOnlyIfNew)(this, crioedReduction); | ||
} | ||
if (!isCrio(itemValue)) { | ||
itemValue = crio(itemValue); | ||
/** | ||
* based on fn, reduceRight the CrioArray and return either the crio of the reduced object | ||
* or the object itself | ||
* | ||
* @param {function} fn | ||
* @param {any} object | ||
* @param {any} thisArg | ||
* @returns {any} | ||
*/ | ||
}, { | ||
key: 'reduceRight', | ||
value: function reduceRight(fn, object) { | ||
var thisArg = arguments.length <= 2 || arguments[2] === undefined ? this : arguments[2]; | ||
var reduction = ARRAY_PROTOTYPE.reduceRight.call(this, fn, object, thisArg); | ||
var crioedReduction = getRealValue(reduction); | ||
return !crioedReduction || !crioedReduction.$$hashCode ? crioedReduction : (0, _utils.returnObjectOnlyIfNew)(this, crioedReduction); | ||
} | ||
/** | ||
* set key to value in this and return new CrioArray | ||
* | ||
* @param {number} key | ||
* @param {any} value | ||
* | ||
* @returns {CrioArray} | ||
*/ | ||
}, { | ||
key: 'set', | ||
value: function set(key, value) { | ||
var index = +key; | ||
if (index > this.length) { | ||
throw new Error('Cannot set a key for sparsed array on crio objects.'); | ||
} | ||
var clone = this.thaw(); | ||
clone[index] = value; | ||
var crioedArray = new CrioArray(clone); | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedArray); | ||
} | ||
/** | ||
* deeply assign value to key in this and return new CrioArray | ||
* | ||
* @param {array<string|number>} keys | ||
* @param {any} value | ||
* @returns {CrioArray} | ||
*/ | ||
}, { | ||
key: 'setIn', | ||
value: function setIn(keys, value) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
throw new Error('Must provide keys as an array, such as ["foo", "bar"].'); | ||
} | ||
return assignOnDeepMatch(this, keys, value); | ||
} | ||
/** | ||
* return this with first item removed as new CrioArray | ||
* | ||
* @returns {CrioArray} | ||
*/ | ||
}, { | ||
key: 'shift', | ||
value: function shift() { | ||
return this.slice(1, this.length); | ||
} | ||
/** | ||
* return a section of this as a new CrioArray | ||
* | ||
* @param {array<number>} args | ||
* @returns {CrioArray} | ||
*/ | ||
}, { | ||
key: 'slice', | ||
value: function slice() { | ||
var _ARRAY_PROTOTYPE$slic; | ||
for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { | ||
args[_key4] = arguments[_key4]; | ||
} | ||
if (!args.length) { | ||
return this; | ||
} | ||
return new CrioArray((_ARRAY_PROTOTYPE$slic = ARRAY_PROTOTYPE.slice).call.apply(_ARRAY_PROTOTYPE$slic, [this].concat(args))); | ||
} | ||
}, { | ||
key: 'some', | ||
/** | ||
* does some of the returns from fn return truthy | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
* @returns {boolean} | ||
*/ | ||
value: function some(fn) { | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
for (var index = 0, length = this.length; index < length; index++) { | ||
if (fn.call(thisArg, this[index], index, this)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
/** | ||
* sort this and return it as a new CrioArray | ||
* | ||
* @param {function} fn | ||
* @returns {CrioArray} | ||
*/ | ||
}, { | ||
key: 'sort', | ||
value: function sort(fn) { | ||
var sortedArray = this.thaw().sort(fn); | ||
var crioedArray = new CrioArray(sortedArray); | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedArray); | ||
} | ||
/** | ||
* based on args passed, splice this and return it as a new CrioArray | ||
* | ||
* @param {any} args | ||
* @returns {CrioArray} | ||
*/ | ||
}, { | ||
key: 'splice', | ||
value: function splice() { | ||
var clone = this.thaw(); | ||
clone.splice.apply(clone, arguments); | ||
var crioedArray = new CrioArray(clone); | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedArray); | ||
} | ||
/** | ||
* convert this back to a vanilla array | ||
* | ||
* @returns {array<any>} | ||
*/ | ||
}, { | ||
key: 'thaw', | ||
value: function thaw() { | ||
return ARRAY_PROTOTYPE.map.call(this, function (item) { | ||
return isCrio(item) ? item.thaw() : item; | ||
}); | ||
} | ||
/** | ||
* convert this to a locale-specific string | ||
* | ||
* @returns {string} | ||
*/ | ||
}, { | ||
key: 'toLocaleString', | ||
value: function toLocaleString() { | ||
return this.toString(); | ||
} | ||
/** | ||
* convert this to a string showing key: value pair combos | ||
* | ||
* @returns {string} | ||
*/ | ||
}, { | ||
key: 'toString', | ||
value: function toString() { | ||
var _this5 = this; | ||
var string = 'CrioArray {'; | ||
this.keys().forEach(function (key, keyIndex) { | ||
if (keyIndex !== 0) { | ||
string += ', '; | ||
} | ||
var value = _this5[key]; | ||
var cleanValue = isCrio(value) ? value.toString() : '"' + value + '"'; | ||
string += key + ': ' + cleanValue; | ||
}); | ||
string += '}'; | ||
return string; | ||
} | ||
/** | ||
* add items to the beginning of this and return it as a new CrioArray | ||
* | ||
* @param {array<any>} items | ||
* @returns {CrioArray} | ||
*/ | ||
}, { | ||
key: 'unshift', | ||
value: function unshift() { | ||
for (var _len5 = arguments.length, items = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { | ||
items[_key5] = arguments[_key5]; | ||
} | ||
if (!items.length) { | ||
return this; | ||
} | ||
return new CrioArray([].concat(items, _toConsumableArray(this))); | ||
} | ||
/** | ||
* get the iterable array of values for this | ||
* | ||
* @returns {array<any>} | ||
*/ | ||
}, { | ||
key: 'values', | ||
value: function values() { | ||
return OBJECT_VALUES(this); | ||
} | ||
/** | ||
* make CrioArray into an iterable | ||
* | ||
* @returns {{next: (function(): {value: any, done: boolean})}} | ||
*/ | ||
}, { | ||
key: Symbol.iterator, | ||
value: function value() { | ||
var _this6 = this; | ||
var index = 0; | ||
return { | ||
next: function next() { | ||
var value = _this6[index]; | ||
var done = index >= _this6.length; | ||
index++; | ||
return { | ||
value: value, | ||
done: done | ||
}; | ||
} | ||
}; | ||
} | ||
}, { | ||
key: '$$hashCode', | ||
get: function get() { | ||
return (0, _utils.hash)(this.toString()); | ||
} | ||
/** | ||
* return type of CrioArray | ||
* | ||
* @return {string} | ||
*/ | ||
}, { | ||
key: '$$type', | ||
get: function get() { | ||
return 'CrioArray'; | ||
} | ||
}]); | ||
return CrioArray; | ||
}(); | ||
var CrioObject = function () { | ||
function CrioObject(object) { | ||
_classCallCheck(this, CrioObject); | ||
if (isCrio(object)) { | ||
return object; | ||
} | ||
var keys = OBJECT_OWN_PROPERTY_NAMES(object).filter(function (key) { | ||
return NATIVE_KEYS.indexOf(key) === -1; | ||
}); | ||
var length = keys.length; | ||
for (var index = 0; index < length; index++) { | ||
var key = keys[index]; | ||
var value = getRealValue(object[key]); | ||
(0, _utils.setReadOnly)(this, key, value, object.propertyIsEnumerable(key)); | ||
} | ||
return OBJECT_FREEZE(this); | ||
} | ||
setCrioIdentifier(crioedObject); | ||
(0, _utils.setImmutable)(crioedObject, property, itemValue, GET_OWN_PROPERTY_DESCRIPTOR(object, property)); | ||
}); | ||
/** | ||
* return unique hash of this values | ||
* | ||
* @return {number} | ||
*/ | ||
return FREEZE(crioedObject); | ||
}; | ||
var crio = function crio() { | ||
var object = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
_createClass(CrioObject, [{ | ||
key: 'entries', | ||
if (isCrio(object)) { | ||
return object; | ||
} | ||
if ((0, _utils.isArray)(object)) { | ||
return crioArray(object); | ||
} | ||
/** | ||
* return iterable array of keys in this | ||
* | ||
* @returns {array<string>} | ||
*/ | ||
value: function entries() { | ||
return OBJECT_ENTRIES(this); | ||
} | ||
if ((0, _utils.isObject)(object)) { | ||
return crioObject(object); | ||
} | ||
/** | ||
* is the object passed equal in value to this | ||
* | ||
* @param {any} object | ||
* @returns {boolean} | ||
*/ | ||
return object; | ||
}; | ||
}, { | ||
key: 'equals', | ||
value: function equals(object) { | ||
if (!isCrio(object)) { | ||
return false; | ||
} | ||
crio.array = function () { | ||
var array = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; | ||
return this.$$hashCode === object.$$hashCode; | ||
} | ||
return crioArray(array); | ||
}; | ||
/** | ||
* return value at key in this | ||
* | ||
* @param {string} key | ||
* @returns {any} | ||
*/ | ||
crio.array.from = function () { | ||
for (var _len9 = arguments.length, args = Array(_len9), _key9 = 0; _key9 < _len9; _key9++) { | ||
args[_key9] = arguments[_key9]; | ||
} | ||
}, { | ||
key: 'get', | ||
value: function get(key) { | ||
return this[key.toString()]; | ||
} | ||
return crioArray(args); | ||
}; | ||
/** | ||
* return value at nested point based on keys in this | ||
* | ||
* @param {array<string|number>} keys | ||
* @return {any} | ||
*/ | ||
crio.object = function () { | ||
var object = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
}, { | ||
key: 'getIn', | ||
value: function getIn(keys) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
throw new Error('Must provide keys as an array, such as ["foo", "bar"].'); | ||
} | ||
return crioObject(object); | ||
var length = keys.length; | ||
var lastIndex = length - 1; | ||
var currentObject = this; | ||
for (var index = 0; index < length; index++) { | ||
var key = keys[index]; | ||
if ((0, _utils.isUndefined)(currentObject[key]) || index === lastIndex) { | ||
return currentObject[key]; | ||
} | ||
currentObject = currentObject[key]; | ||
} | ||
} | ||
}, { | ||
key: 'hasOwnProperty', | ||
/** | ||
* return if this has the property passed | ||
* | ||
* @param {string} property | ||
* @returns {boolean} | ||
*/ | ||
value: function hasOwnProperty(property) { | ||
return OBJECT_PROTOTYPE.hasOwnProperty.call(this, property); | ||
} | ||
/** | ||
* return if this has the prototype of object passed | ||
* | ||
* @param {any} object | ||
* @returns {boolean} | ||
*/ | ||
}, { | ||
key: 'isPrototypeOf', | ||
value: function isPrototypeOf(object) { | ||
return OBJECT_PROTOTYPE.isPrototypeOf.call(this, object); | ||
} | ||
/** | ||
* return iterable of keys in this | ||
* | ||
* @returns {array<string>} | ||
*/ | ||
}, { | ||
key: 'keys', | ||
value: function keys() { | ||
return OBJECT_KEYS(this); | ||
} | ||
/** | ||
* shallowly merge all objects into this and return as new CrioObject | ||
* | ||
* @param {array<any>} objects | ||
* @returns {CrioObject} | ||
*/ | ||
}, { | ||
key: 'merge', | ||
value: function merge() { | ||
var clone = isCrio(this) ? this.thaw() : this; | ||
for (var _len6 = arguments.length, objects = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { | ||
objects[_key6] = arguments[_key6]; | ||
} | ||
objects.forEach(function (object) { | ||
Object.assign(clone, object); | ||
}); | ||
var crioedObject = new CrioObject(clone); | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedObject); | ||
} | ||
/** | ||
* deeply merge all objects into this at key value determined by keys, | ||
* and return as a new CrioObject | ||
* | ||
* @param {array<string|number>} keys | ||
* @param {array<any>} objects | ||
* @returns {CrioObject} | ||
*/ | ||
}, { | ||
key: 'mergeIn', | ||
value: function mergeIn(keys) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
throw new Error('Must provide keys as an array, such as ["foo", "bar"].'); | ||
} | ||
for (var _len7 = arguments.length, objects = Array(_len7 > 1 ? _len7 - 1 : 0), _key7 = 1; _key7 < _len7; _key7++) { | ||
objects[_key7 - 1] = arguments[_key7]; | ||
} | ||
if (!objects.length) { | ||
return this; | ||
} | ||
return assignOnDeepMatch(this, keys, objects, true); | ||
} | ||
/** | ||
* convenience function to work with mutable version of this, | ||
* in case many modifications need to be made and performance | ||
* is paramount | ||
* | ||
* @param {function} fn | ||
* @param {any} thisArg | ||
* @returns {any} | ||
*/ | ||
}, { | ||
key: 'mutate', | ||
value: function mutate(fn) { | ||
var thisArg = arguments.length <= 1 || arguments[1] === undefined ? this : arguments[1]; | ||
var result = fn.call(thisArg, this.thaw(), this); | ||
var crioedValue = getRealValue(result); | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedValue); | ||
} | ||
/** | ||
* determine if property passed is enumerable in this | ||
* | ||
* @param {string} property | ||
* @returns {boolean} | ||
*/ | ||
}, { | ||
key: 'propertyIsEnumerable', | ||
value: function propertyIsEnumerable(property) { | ||
return OBJECT_PROTOTYPE.propertyIsEnumerable.call(this, property); | ||
} | ||
/** | ||
* set value at key in this | ||
* | ||
* @param {string} key | ||
* @param {any} value | ||
* @returns {CrioObject} | ||
*/ | ||
}, { | ||
key: 'set', | ||
value: function set(key, value) { | ||
var clone = this.thaw(); | ||
clone[key] = value; | ||
var crioedObject = new CrioObject(clone); | ||
return (0, _utils.returnObjectOnlyIfNew)(this, crioedObject); | ||
} | ||
/** | ||
* deeply set value at location determined by keys in this | ||
* | ||
* @param {array<string|number>} keys | ||
* @param {any} value | ||
* @returns {CrioObject} | ||
*/ | ||
}, { | ||
key: 'setIn', | ||
value: function setIn(keys, value) { | ||
if (!(0, _utils.isArray)(keys)) { | ||
throw new Error('Must provide keys as an array, such as ["foo", "bar"].'); | ||
} | ||
return assignOnDeepMatch(this, keys, value); | ||
} | ||
/** | ||
* convert this back to a vanilla array | ||
* | ||
* @returns {array<any>} | ||
*/ | ||
}, { | ||
key: 'thaw', | ||
value: function thaw() { | ||
var _this7 = this; | ||
return OBJECT_OWN_PROPERTY_NAMES(this).reduce(function (object, key) { | ||
if (NATIVE_KEYS.indexOf(key) === -1) { | ||
var value = _this7[key]; | ||
var cleanValue = isCrio(value) ? value.thaw() : value; | ||
(0, _utils.setStandard)(object, key, cleanValue, _this7.propertyIsEnumerable(key)); | ||
} | ||
return object; | ||
}, {}); | ||
} | ||
/** | ||
* convert this to a locale-specific string | ||
* | ||
* @returns {string} | ||
*/ | ||
}, { | ||
key: 'toLocaleString', | ||
value: function toLocaleString() { | ||
return this.toString(); | ||
} | ||
/** | ||
* convert this to a string showing key: value pair combos | ||
* | ||
* @returns {string} | ||
*/ | ||
}, { | ||
key: 'toString', | ||
value: function toString() { | ||
var _this8 = this; | ||
var startString = 'CrioObject {'; | ||
var string = startString; | ||
OBJECT_OWN_PROPERTY_NAMES(this).forEach(function (key) { | ||
if (NATIVE_KEYS.indexOf(key) === -1) { | ||
if (string !== startString) { | ||
string += ', '; | ||
} | ||
var value = _this8[key]; | ||
var cleanValue = isCrio(value) ? value.toString() : '"' + value + '"'; | ||
string += '"' + key + '": ' + cleanValue; | ||
} | ||
}); | ||
string += '}'; | ||
return string; | ||
} | ||
/** | ||
* get the valueOf for this | ||
* | ||
* @return {any} | ||
*/ | ||
}, { | ||
key: 'valueOf', | ||
value: function valueOf() { | ||
return OBJECT_PROTOTYPE.valueOf.call(this); | ||
} | ||
/** | ||
* get the iterable array of values for this | ||
* | ||
* @returns {array<any>} | ||
*/ | ||
}, { | ||
key: 'values', | ||
value: function values() { | ||
return OBJECT_VALUES(this); | ||
} | ||
/** | ||
* make CrioObject into an iterable | ||
* | ||
* @returns {{next: (function(): {value: any, done: boolean})}} | ||
*/ | ||
}, { | ||
key: Symbol.iterator, | ||
value: function value() { | ||
var _this9 = this; | ||
var keys = OBJECT_KEYS(this); | ||
var index = 0; | ||
return { | ||
next: function next() { | ||
var key = keys[index]; | ||
var value = _this9[key]; | ||
var done = index >= _this9.length; | ||
index++; | ||
return { | ||
value: value, | ||
done: done | ||
}; | ||
} | ||
}; | ||
} | ||
}, { | ||
key: '$$hashCode', | ||
get: function get() { | ||
return (0, _utils.hash)(this.toString()); | ||
} | ||
/** | ||
* return type of CrioObject | ||
* | ||
* @return {string} | ||
*/ | ||
}, { | ||
key: '$$type', | ||
get: function get() { | ||
return 'CrioObject'; | ||
} | ||
/** | ||
* return number of keys in object (getter here because it will show up in console, | ||
* whereas for CrioArray it is an expected property and is appropriately hidden) | ||
* | ||
* @return {number} | ||
*/ | ||
}, { | ||
key: 'length', | ||
get: function get() { | ||
var keys = OBJECT_OWN_PROPERTY_NAMES(this).filter(function (key) { | ||
return NATIVE_KEYS.indexOf(key) === -1; | ||
}); | ||
return keys.length; | ||
} | ||
}]); | ||
return CrioObject; | ||
}(); | ||
/** | ||
* entry function, assigning to either CrioArray or CrioObject or neither | ||
* | ||
* @param {any} object | ||
* @return {any} | ||
*/ | ||
var crio = function crio(object) { | ||
if ((0, _utils.isArray)(object)) { | ||
return new CrioArray(object); | ||
} | ||
if ((0, _utils.isObject)(object)) { | ||
return new CrioObject(object); | ||
} | ||
return object; | ||
}; | ||
exports.default = crio; | ||
module.exports = exports['default']; | ||
exports.assignOnDeepMatch = assignOnDeepMatch; | ||
exports.getRealValue = getRealValue; | ||
exports.isCrio = isCrio; | ||
exports.CrioArray = CrioArray; | ||
exports.CrioObject = CrioObject; | ||
exports.default = crio; |
236
lib/utils.js
'use strict'; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.setImmutable = exports.getRestOfObject = exports.getMutableObject = exports.isUndefined = exports.isObject = exports.isEqual = exports.isArray = exports.coerceToInteger = undefined; | ||
exports.setStandard = exports.setReadOnly = exports.setNonEnumerable = exports.returnObjectOnlyIfNew = exports.isUndefined = exports.isObject = exports.isArray = exports.hash = undefined; | ||
var _crioIdentifier = require('./crioIdentifier'); | ||
var _murmurhash3js = require('murmurhash3js'); | ||
var _crioIdentifier2 = _interopRequireDefault(_crioIdentifier); | ||
var _murmurhash3js2 = _interopRequireDefault(_murmurhash3js); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var DEFINE_PROPERTY = Object.defineProperty; | ||
var GET_OWN_PROPERTY_NAMES = Object.getOwnPropertyNames; | ||
var TO_STRING = Object.prototype.toString; | ||
var HASH_SEED = 13; | ||
var coerceToInteger = exports.coerceToInteger = function coerceToInteger(value) { | ||
return +value | 0; | ||
/** | ||
* apply Object's prototypical toString to object | ||
* | ||
* @param {any} object | ||
* @return {string} | ||
*/ | ||
var toString = function toString(object) { | ||
return Object.prototype.toString.call(object); | ||
}; | ||
var isArray = exports.isArray = function isArray(object) { | ||
return TO_STRING.call(object) === '[object Array]'; | ||
/** | ||
* hash string using murmur3 hashing algorithm | ||
* | ||
* @param {string} string | ||
* @returns {string} | ||
*/ | ||
var hash = function hash(string) { | ||
return _murmurhash3js2.default.x86.hash32(string, HASH_SEED); | ||
}; | ||
var isEqual = exports.isEqual = function isEqual(object1, object2) { | ||
if (object1 === object2) { | ||
return true; | ||
} | ||
if (!(isArray(object1) || isArray(object2)) && !(isObject(object1) || isObject(object2))) { | ||
return false; | ||
} | ||
if (object1.prototype !== object2.prototype) { | ||
return false; | ||
} | ||
var object1Properties = GET_OWN_PROPERTY_NAMES(object1); | ||
var object2Properties = GET_OWN_PROPERTY_NAMES(object2); | ||
var object1PropertiesLength = object1Properties.length; | ||
if (object1PropertiesLength !== object2Properties.length) { | ||
return false; | ||
} | ||
for (var index = 0; index < object1PropertiesLength; index++) { | ||
var object1Value = object1[object1Properties[index]]; | ||
var object2Value = object2[object2Properties[index]]; | ||
if (object1Value !== object2Value) { | ||
return false; | ||
} | ||
if ((typeof object1Value === 'undefined' ? 'undefined' : _typeof(object1Value)) !== (typeof object2Value === 'undefined' ? 'undefined' : _typeof(object2Value))) { | ||
return false; | ||
} | ||
if (isArray(object1Value) || isObject(object1Value)) { | ||
return isEqual(object1Value, object2Value); | ||
} | ||
} | ||
return true; | ||
/** | ||
* determine if object is array | ||
* | ||
* @param {any} object | ||
* @return {boolean} | ||
*/ | ||
var isArray = function isArray(object) { | ||
return toString(object) === '[object Array]' || !!(object && object.$$type === 'CrioArray'); | ||
}; | ||
var isObject = exports.isObject = function isObject(object) { | ||
return TO_STRING.call(object) === '[object Object]' && !!object; | ||
/** | ||
* determine if object is object | ||
* | ||
* @param {any} object | ||
* @return {boolean} | ||
*/ | ||
var isObject = function isObject(object) { | ||
return toString(object) === '[object Object]' && !!object && object.$$type !== 'CrioArray' || !!(object && object.$$type === 'CrioObject'); | ||
}; | ||
var isUndefined = exports.isUndefined = function isUndefined(object) { | ||
return object === void 0; | ||
/** | ||
* determine if object is undefined | ||
* | ||
* @param {any} object | ||
* @return {boolean} | ||
*/ | ||
var isUndefined = function isUndefined(object) { | ||
return object === void 0; | ||
}; | ||
var setMutableProperty = function setMutableProperty(object, property, targetObject) { | ||
var descriptor = Object.getOwnPropertyDescriptor(object, property) || {}; | ||
/** | ||
* based on hashCodes, either return the current object or the newly generated on | ||
* | ||
* @param {object} currentObject={} | ||
* @param {object} newObject={} | ||
* @return {object<T>} | ||
*/ | ||
var returnObjectOnlyIfNew = function returnObjectOnlyIfNew() { | ||
var currentObject = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
var newObject = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
var value = object[property]; | ||
if (currentObject.$$hashCode !== newObject.$$hashCode) { | ||
return newObject; | ||
} | ||
if (isArray(value) || isObject(value)) { | ||
value = getMutableObject(value); | ||
} | ||
DEFINE_PROPERTY(targetObject, property, { | ||
configurable: true, | ||
enumerable: descriptor.enumerable || true, | ||
value: value, | ||
writable: true | ||
}); | ||
return currentObject; | ||
}; | ||
var getMutableObject = exports.getMutableObject = function getMutableObject(object) { | ||
var isObjectArray = isArray(object); | ||
var mutableObject = isObjectArray ? [] : {}; | ||
if (isObjectArray) { | ||
object.forEach(function (item, itemIndex) { | ||
setMutableProperty(object, itemIndex, mutableObject); | ||
/** | ||
* set property in object to be non-enumerable | ||
* | ||
* @param {object} object | ||
* @param {string} property | ||
* @param {any} value | ||
*/ | ||
var setNonEnumerable = function setNonEnumerable(object, property, value) { | ||
Object.defineProperty(object, property, { | ||
configurable: false, | ||
enumerable: false, | ||
value: value, | ||
writable: false | ||
}); | ||
} else { | ||
GET_OWN_PROPERTY_NAMES(object).forEach(function (property) { | ||
if (property !== _crioIdentifier2.default) { | ||
setMutableProperty(object, property, mutableObject); | ||
} | ||
}); | ||
} | ||
return mutableObject; | ||
}; | ||
var getRestOfObject = exports.getRestOfObject = function getRestOfObject(object, key) { | ||
if (isArray(object)) { | ||
return object.filter(function (item, itemIndex) { | ||
return itemIndex !== key; | ||
/** | ||
* set property in object to be readonly (not configurable or writable) | ||
* | ||
* @param {object} object | ||
* @param {string} property | ||
* @param {any} value | ||
* @param {boolean} enumerable=true | ||
*/ | ||
var setReadOnly = function setReadOnly(object, property, value) { | ||
var enumerable = arguments.length <= 3 || arguments[3] === undefined ? true : arguments[3]; | ||
Object.defineProperty(object, property, { | ||
configurable: false, | ||
enumerable: enumerable, | ||
value: value, | ||
writable: false | ||
}); | ||
} | ||
var tempObject = _extends({}, object); | ||
delete tempObject[key]; | ||
return tempObject; | ||
}; | ||
var setImmutable = exports.setImmutable = function setImmutable(object, property, value) { | ||
var descriptor = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3]; | ||
/** | ||
* set property in object to be standard (configurable and writable) | ||
* | ||
* @param {object} object | ||
* @param {string} property | ||
* @param {any} value | ||
* @param {boolean} enumerable=true | ||
*/ | ||
var setStandard = function setStandard(object, property, value) { | ||
var enumerable = arguments.length <= 3 || arguments[3] === undefined ? true : arguments[3]; | ||
DEFINE_PROPERTY(object, property, { | ||
get: function get() { | ||
return value; | ||
}, | ||
set: function set() { | ||
throw new SyntaxError('Cannot set the value for this object property directly, please use either the .set() or .setIn() method.'); | ||
}, | ||
configurable: false, | ||
enumerable: descriptor.enumerable || true | ||
}); | ||
return object[property]; | ||
Object.defineProperty(object, property, { | ||
configurable: true, | ||
enumerable: enumerable, | ||
value: value, | ||
writable: true | ||
}); | ||
}; | ||
exports.default = { | ||
coerceToInteger: coerceToInteger, | ||
getMutableObject: getMutableObject, | ||
getRestOfObject: getRestOfObject, | ||
isArray: isArray, | ||
isEqual: isEqual, | ||
isObject: isObject, | ||
isUndefined: isUndefined, | ||
setImmutable: setImmutable | ||
}; | ||
exports.hash = hash; | ||
exports.isArray = isArray; | ||
exports.isObject = isObject; | ||
exports.isUndefined = isUndefined; | ||
exports.returnObjectOnlyIfNew = returnObjectOnlyIfNew; | ||
exports.setNonEnumerable = setNonEnumerable; | ||
exports.setReadOnly = setReadOnly; | ||
exports.setStandard = setStandard; |
{ | ||
"author": "planttheidea", | ||
"ava": { | ||
"babel": "inherit", | ||
"failFast": true, | ||
"files": [ | ||
"./test/utils.js", | ||
"./test/index.js" | ||
], | ||
"require": [ | ||
"babel-register", | ||
"babel-polyfill" | ||
] | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/planttheidea/crio/issues" | ||
}, | ||
"dependencies": { | ||
"core-js": "^2.4.0", | ||
"murmurhash3js": "^3.0.1" | ||
}, | ||
"description": "Immutable JS ojbects with a natural API", | ||
"devDependencies": { | ||
"babel": "6.3.26", | ||
"babel-cli": "6.4.5", | ||
"babel-eslint": "5.0.0-beta6", | ||
"babel-loader": "6.2.2", | ||
"babel-plugin-add-module-exports": "0.1.2", | ||
"babel-preset-es2015": "6.3.13", | ||
"babel-preset-react": "6.3.13", | ||
"babel-preset-stage-0": "6.3.13", | ||
"ejs": "2.4.1", | ||
"eslint": "1.10.3", | ||
"eslint-friendly-formatter": "1.2.2", | ||
"eslint-loader": "1.2.1", | ||
"eslint-plugin-babel": "3.1.0", | ||
"eslint-plugin-react": "3.16.1", | ||
"expect": "1.14.0", | ||
"react": "0.14.7", | ||
"react-dom": "0.14.7", | ||
"webpack": "1.12.13", | ||
"ava": "^0.15.2", | ||
"babel": "6.5.2", | ||
"babel-cli": "6.10.1", | ||
"babel-eslint": "6.1.0", | ||
"babel-loader": "6.2.4", | ||
"babel-plugin-add-module-exports": "0.2.1", | ||
"babel-polyfill": "^6.9.1", | ||
"babel-preset-es2015": "6.9.0", | ||
"babel-preset-react": "6.5.0", | ||
"babel-preset-stage-0": "6.5.0", | ||
"babel-register": "^6.9.0", | ||
"ejs": "2.4.2", | ||
"eslint": "2.13.1", | ||
"eslint-friendly-formatter": "2.0.5", | ||
"eslint-loader": "1.3.0", | ||
"html-webpack-plugin": "^2.21.0", | ||
"react": "^15.1.0", | ||
"react-dom": "^15.1.0", | ||
"webpack": "1.13.1", | ||
"webpack-dev-server": "1.14.1" | ||
@@ -30,5 +47,4 @@ }, | ||
"keywords": [ | ||
"crio", | ||
"immutable", | ||
"immutablejs" | ||
"crio" | ||
], | ||
@@ -43,9 +59,12 @@ "license": "MIT", | ||
"scripts": { | ||
"build": "NODE_ENV=development ./node_modules/webpack/bin/webpack.js --progress", | ||
"build-minified": "NODE_ENV=production ./node_modules/webpack/bin/webpack.js --progress --config=webpack.config.minified.js", | ||
"compile": "./node_modules/babel-cli/lib/babel/index.js -d lib/ src/", | ||
"dist": "npm run compile && npm run build && npm run build-minified", | ||
"test": "NODE_ENV=test ./node_modules/webpack-dev-server/bin/webpack-dev-server.js --progress --config=webpack.config.test.js" | ||
"build": "NODE_ENV=development ./node_modules/webpack/bin/webpack.js --progress --colors", | ||
"build-minified": "NODE_ENV=production ./node_modules/webpack/bin/webpack.js --progress --colors --config=webpack.config.minified.js", | ||
"dev": "NODE_ENV=development ./node_modules/webpack-dev-server/bin/webpack-dev-server.js --progress --colors --config=webpack.config.dev.js", | ||
"lint": "NODE_ENV=test ./node_modules/eslint/bin/eslint.js src", | ||
"prepublish": "npm run lint && npm run test && npm run transpile && npm run build && npm run build-minified", | ||
"test": "NODE_ENV=test ava --no-cache", | ||
"test:watch": "NODE_ENV=test ava --no-cache --watch", | ||
"transpile": "./node_modules/babel-cli/lib/babel/index.js -d lib/ src/" | ||
}, | ||
"version": "1.0.1" | ||
"version": "2.0.0" | ||
} |
# crio | ||
Immutable JS that doesn't get in your way | ||
Immutable JS objects with a natural API | ||
@@ -7,20 +7,14 @@ #### Jump to the API | ||
#### Installation | ||
For built projects with webpack / browserify: | ||
``` | ||
npm i crio --save | ||
``` | ||
And to use in your file: | ||
``` | ||
// CommonJS | ||
var crio = require('crio'); | ||
#### Usage | ||
```javascript | ||
// ES2015 | ||
import crio from 'crio'; | ||
``` | ||
For traditional inclusion of library by script tag (pulled from dist folder): | ||
// CommonJS | ||
const crio = require('crio').default; | ||
// UMD | ||
const crio = window.crio; | ||
``` | ||
<script src="crio.min.js"></script> | ||
``` | ||
@@ -34,3 +28,3 @@ #### What is immutable? | ||
The concept of immutability already exists in a lot of places in JavaScript, for example: | ||
``` | ||
```javascript | ||
const two = 2; | ||
@@ -41,3 +35,3 @@ const three = 3; | ||
By adding together *two* and *three* you expect to get *five*, however you don't expect the value of *two* to change. You can continue working with it even after using it in an expression: | ||
``` | ||
```javascript | ||
const two = 2; | ||
@@ -49,13 +43,13 @@ const three = 3; | ||
This is true of strings, numbers, undefined, and null, and is an expected behavior. The same idea, however, is not true for complex objects in JavaScfript. For example: | ||
``` | ||
```javascript | ||
const foo = ['foo']; | ||
const bar = foo.push('bar'); | ||
const fooBar = foo.push('bar'); | ||
``` | ||
The expectation is that you have pushed the value of "bar" into *foo* and created a new array *bar* that contains "foo, bar", however in reality this is what happens: | ||
``` | ||
```javascript | ||
const foo = ['foo']; | ||
const bar = foo.push('bar'); | ||
const fooBar = foo.push('bar'); | ||
console.log(foo); // ['foo', 'bar'] | ||
console.log(bar); // 1 | ||
console.log(fooBar); // 1 | ||
``` | ||
@@ -66,3 +60,3 @@ Basically, you have mutated *foo* so that it is no longer empty, and what the *.push()* method returns is actually the index of the item you just added. This double-standard of expectations creates a lot confusion from a development perspective, but also makes keeping track of the state of your application very difficult because there is no traceability of what transactions have occurred to create that state at any given point. | ||
crio attempts to solve the problem by "closing the immutable loop", meaning it applies immutability to objects that are normally mutable by nature by replacing mutating methods with immutable counterparts. As a point of reference: | ||
crio attempts to solve the problem by closing the "immutable loop" on collection items, meaning it applies immutability to objects that are normally mutable by nature by replacing mutating methods with immutable counterparts. As a point of reference: | ||
@@ -77,25 +71,22 @@ *Naturally immutable objects* | ||
* Arrays | ||
* Dates (not covered by crio) | ||
* Objects | ||
To create a new crio object, its pretty straightforward: | ||
``` | ||
```javascript | ||
const crioArray = crio([]); | ||
const crioObject = crio({}); | ||
``` | ||
These are examples with empty objects, but you can pass in populated objects as well, or if you pass in nothing it will default to an object. What crio does is clone and freeze the object via [Object.freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze), and stores it with the new crio prototype. | ||
These are examples with empty objects, but you can pass in populated objects as well, or if you pass in nothing it will default to an object. What crio does is clone and freeze the object via [Object.freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze), and stores as a custom `CrioArray` or `CrioObject` with a prototypical methods that will return a new immutable version of the object with each update. Example: | ||
After the initial instantiation, you can apply changes by methods, but you must assign them to a new variable: | ||
``` | ||
const crioArrayWithValue = crioArray.push(1); | ||
```javascript | ||
const foo = crio(['foo']); | ||
const fooBar = foo.push('bar'); | ||
crioArray.log(); // [] | ||
crioArrayWithValue.log(); // [1] | ||
console.log(foo); // ['foo'] | ||
console.log(fooBar); // ['foo', 'bar'] | ||
``` | ||
Notice that *crioArray* did not change, instead a new array was stored in *crioArrayWithValue*. | ||
The [API](API.md) is the same as you already know working with those objects, and includes polyfills for all ES6 and some ES7 functions, as well as a few helpful crio-specific functions. The only difference is that any setting happens via .set() rather than direct index / property setting. You can work with the objects as you normally would with other libraries (lodash, for example). There is also no change to the protoypes of native objects, so you can apply this on your existing code go-forward. Basically, you shouldn't even notice you aren't working with the native objects, save for the fact everything is immutable. | ||
The [API](API.md) is the same as you already know working with those objects, and adds a few helpful crio-specific functions. The only difference is that any setting happens via .set() or .setIn() rather than direct index / property setting. You can even get values using the traditional object.property or array[index] syntax! | ||
The native constructors are preserved, and so you can work with the objects as you normally would with other libraries (lodash, moment, etc.). There is also no change to the prototypes of native objects, so you can apply this on your existing code go-forward. Basically, you shouldn't even notice you aren't working with the native objects, save for the fact everything is immutable. | ||
#### Why not just use X immutable library? | ||
@@ -108,5 +99,5 @@ | ||
**Immutable** is quite robust and well-accepted, however it creates a classed object that cannot be used with other external libraries (for example, lodash) without converting back and forth. They have a great thing going, however inevitably the inability to use objects like their native counterparts felt like a hinderance. | ||
**Immutable** is quite nice, and their API also follows the object standard (in their case, Array and Map), however it creates a classed object that cannot be used with other external libraries (namely lodash) without converting back and forth. They have a great thing going, however inevitably the inability to use objects like their native counterparts felt like a hinderance. | ||
**mori** is the seasoned veteran, having been hardened via ClosureScript, and for many is chosen specifically because it does not try to "immutify" the default API methods. Personal taste, I wasn't interested in learning an entirely new API (that for a person without a ClosureScript background is rather obtuse). Plus, it's not written in JavaScript ... its compiled to it, which just felt wrong to a JavaScript devout like me. | ||
**mori** is the seasoned veteran, having been hardened via ClosureScript, and for many is chosen specifically because it does not try to immutabilize the default API methods. Personal taste, I wasn't interested in relearning an entirely new API (that for a person without a ClosureScript background is obtuse). Plus, it's not written in JavaScript ... its compiled to it, which just felt wrong to a JavaScript devout like me. | ||
@@ -123,7 +114,6 @@ **seamless-immutable** had great ideas, and I thought that could be the best option because they try to retain the native operations while leveraging Object.freeze, much like crio does. That said, they do not try to replace mutable methods with immutable ones, they just throw errors when you attempt them and its up to you to figure out the "right way". As such, it fell short of my expectations | ||
* Chrome | ||
* Firefox | ||
* Edge | ||
* Firefox | ||
* IE11 | ||
* Opera | ||
This is only because of the youth of the project, as the intended support includes Safari and IE versions 9 and 10. Theoretically these should all work out of the box, just giving fair warning as that is unverified as-of yet. Please report any issues that you encounter. | ||
This is only because of the youth of the project, as the intended support should include Safari, Opera, and IE versions back to 9. Theoretically all of these browsers should work out of the box, I just have not verified it. Please report any issues that you encounter. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
277486
9
2143
2
20
112
1
+ Addedcore-js@^2.4.0
+ Addedmurmurhash3js@^3.0.1
+ Addedcore-js@2.6.12(transitive)
+ Addedmurmurhash3js@3.0.1(transitive)