mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #6388 from gaearon/bye-bye-deprecated-utils
Remove OrderedMap and ReactPropTransferer
(cherry picked from commit b8f8360b5c)
This commit is contained in:
committed by
Paul O’Shannessy
parent
e88c96b1d7
commit
9d73b2339a
@@ -1,505 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule OrderedMap
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
var PREFIX = 'key:';
|
||||
|
||||
/**
|
||||
* Utility to extract a backing object from an initialization `Array`, allowing
|
||||
* the caller to assist in resolving the unique ID for each entry via the
|
||||
* `keyExtractor` callback. The `keyExtractor` must extract non-empty strings or
|
||||
* numbers.
|
||||
* @param {Array<Object!>} arr Array of items.
|
||||
* @param {function} keyExtractor Extracts a unique key from each item.
|
||||
* @return {Object} Map from unique key to originating value that the key was
|
||||
* extracted from.
|
||||
* @throws Exception if the initialization array has duplicate extracted keys.
|
||||
*/
|
||||
function extractObjectFromArray(arr, keyExtractor) {
|
||||
var normalizedObj = {};
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var item = arr[i];
|
||||
var key = keyExtractor(item);
|
||||
assertValidPublicKey(key);
|
||||
var normalizedKey = PREFIX + key;
|
||||
invariant(
|
||||
!(normalizedKey in normalizedObj),
|
||||
'OrderedMap: IDs returned by the key extraction function must be unique.'
|
||||
);
|
||||
normalizedObj[normalizedKey] = item;
|
||||
}
|
||||
return normalizedObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for mappings with ordering. This class is to be used in an
|
||||
* immutable manner. A `OrderedMap` is very much like the native JavaScript
|
||||
* object, where keys map to values via the `get()` function. Also, like the
|
||||
* native JavaScript object, there is an ordering associated with the mapping.
|
||||
* This class is helpful because it eliminates many of the pitfalls that come
|
||||
* with the native JavaScript ordered mappings. Specifically, there are
|
||||
* inconsistencies with numeric keys in some JavaScript implementations
|
||||
* (enumeration ordering). This class protects against those pitfalls and
|
||||
* provides functional utilities for dealing with these `OrderedMap`s.
|
||||
*
|
||||
* - TODO:
|
||||
* - orderedMergeExclusive: Merges mutually exclusive `OrderedMap`s.
|
||||
* - mapReverse().
|
||||
*
|
||||
* @class {OrderedMap}
|
||||
* @constructor {OrderedMap}
|
||||
* @param {Object} normalizedObj Object that is known to be a defensive copy of
|
||||
* caller supplied data. We require a defensive copy to guard against callers
|
||||
* mutating. It is also assumed that the keys of `normalizedObj` have been
|
||||
* normalized and do not contain any numeric-appearing strings.
|
||||
* @param {number} computedLength The precomputed length of `_normalizedObj`
|
||||
* keys.
|
||||
* @private
|
||||
*/
|
||||
function OrderedMapImpl(normalizedObj, computedLength) {
|
||||
this._normalizedObj = normalizedObj;
|
||||
this._computedPositions = null;
|
||||
this.length = computedLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a "public" key - that is, one that the public facing API supplies.
|
||||
* The key is then normalized for internal storage. In order to be considered
|
||||
* valid, all keys must be non-empty, defined, non-null strings or numbers.
|
||||
*
|
||||
* @param {string?} key Validates that the key is suitable for use in a
|
||||
* `OrderedMap`.
|
||||
* @throws Error if key is not appropriate for use in `OrderedMap`.
|
||||
*/
|
||||
function assertValidPublicKey(key) {
|
||||
invariant(
|
||||
key !== '' && (typeof key === 'string' || typeof key === 'number'),
|
||||
'OrderedMap: Key must be non-empty, non-null string or number.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that arguments to range operations are within the correct limits.
|
||||
*
|
||||
* @param {number} start Start of range.
|
||||
* @param {number} length Length of range.
|
||||
* @param {number} actualLen Actual length of range that should not be
|
||||
* exceeded.
|
||||
* @throws Error if range arguments are out of bounds.
|
||||
*/
|
||||
function assertValidRangeIndices(start, length, actualLen) {
|
||||
invariant(
|
||||
typeof start === 'number' &&
|
||||
typeof length === 'number' &&
|
||||
length >= 0 &&
|
||||
start >= 0 &&
|
||||
start + length <= actualLen,
|
||||
'OrderedMap: `mapRange` and `forEachRange` expect non-negative start and ' +
|
||||
'length arguments within the bounds of the instance.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two "normalized" objects (objects who's key have been normalized) into
|
||||
* a `OrderedMap`.
|
||||
*
|
||||
* @param {Object} a Object of key value pairs.
|
||||
* @param {Object} b Object of key value pairs.
|
||||
* @return {OrderedMap} new `OrderedMap` that results in merging `a` and `b`.
|
||||
*/
|
||||
function _fromNormalizedObjects(a, b) {
|
||||
// Second optional, both must be plain JavaScript objects.
|
||||
invariant(
|
||||
a && a.constructor === Object && (!b || b.constructor === Object),
|
||||
'OrderedMap: Corrupted instance of OrderedMap detected.'
|
||||
);
|
||||
|
||||
var newSet = {};
|
||||
var length = 0;
|
||||
var key;
|
||||
for (key in a) {
|
||||
if (a.hasOwnProperty(key)) {
|
||||
newSet[key] = a[key];
|
||||
length++;
|
||||
}
|
||||
}
|
||||
|
||||
for (key in b) {
|
||||
if (b.hasOwnProperty(key)) {
|
||||
// Increment length if not already added via first object (a)
|
||||
if (!(key in newSet)) {
|
||||
length++;
|
||||
}
|
||||
newSet[key] = b[key];
|
||||
}
|
||||
}
|
||||
return new OrderedMapImpl(newSet, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods for `OrderedMap` instances.
|
||||
*
|
||||
* @lends OrderedMap.prototype
|
||||
* TODO: Make this data structure lazy, unify with LazyArray.
|
||||
* TODO: Unify this with ImmutableObject - it is to be used immutably.
|
||||
* TODO: If so, consider providing `fromObject` API.
|
||||
* TODO: Create faster implementation of merging/mapping from original Array,
|
||||
* without having to first create an object - simply for the sake of merging.
|
||||
*/
|
||||
var OrderedMapMethods = {
|
||||
|
||||
/**
|
||||
* Returns whether or not a given key is present in the map.
|
||||
*
|
||||
* @param {string} key Valid string key to lookup membership for.
|
||||
* @return {boolean} Whether or not `key` is a member of the map.
|
||||
* @throws Error if provided known invalid key.
|
||||
*/
|
||||
has: function(key) {
|
||||
assertValidPublicKey(key);
|
||||
var normalizedKey = PREFIX + key;
|
||||
return normalizedKey in this._normalizedObj;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the object for a given key, or `undefined` if not present. To
|
||||
* distinguish an undefined entry vs not being in the set, use `has()`.
|
||||
*
|
||||
* @param {string} key String key to lookup the value for.
|
||||
* @return {Object?} Object at key `key`, or undefined if not in map.
|
||||
* @throws Error if provided known invalid key.
|
||||
*/
|
||||
get: function(key) {
|
||||
assertValidPublicKey(key);
|
||||
var normalizedKey = PREFIX + key;
|
||||
return this.has(key) ? this._normalizedObj[normalizedKey] : undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Merges, appending new keys to the end of the ordering. Keys in `orderedMap`
|
||||
* that are redundant with `this`, maintain the same ordering index that they
|
||||
* had in `this`. This is how standard JavaScript object merging would work.
|
||||
* If you wish to prepend a `OrderedMap` to the beginning of another
|
||||
* `OrderedMap` then simply reverse the order of operation. This is the analog
|
||||
* to `merge(x, y)`.
|
||||
*
|
||||
* @param {OrderedMap} orderedMap OrderedMap to merge onto the end.
|
||||
* @return {OrderedMap} New OrderedMap that represents the result of the
|
||||
* merge.
|
||||
*/
|
||||
merge: function(orderedMap) {
|
||||
invariant(
|
||||
orderedMap instanceof OrderedMapImpl,
|
||||
'OrderedMap.merge(...): Expected an OrderedMap instance.'
|
||||
);
|
||||
return _fromNormalizedObjects(
|
||||
this._normalizedObj,
|
||||
orderedMap._normalizedObj
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Functional map API. Returns a new `OrderedMap`.
|
||||
*
|
||||
* @param {Function} cb Callback to invoke for each item.
|
||||
* @param {Object?=} context Context to invoke callback from.
|
||||
* @return {OrderedMap} OrderedMap that results from mapping.
|
||||
*/
|
||||
map: function(cb, context) {
|
||||
return this.mapRange(cb, 0, this.length, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* The callback `cb` is invoked with the arguments (item, key,
|
||||
* indexInOriginal).
|
||||
*
|
||||
* @param {Function} cb Determines result for each item.
|
||||
* @param {number} start Start index of map range.
|
||||
* @param {end} length End index of map range.
|
||||
* @param {*!?} context Context of callback invocation.
|
||||
* @return {OrderedMap} OrderedMap resulting from mapping the range.
|
||||
*/
|
||||
mapRange: function(cb, start, length, context) {
|
||||
var thisSet = this._normalizedObj;
|
||||
var newSet = {};
|
||||
var i = 0;
|
||||
assertValidRangeIndices(start, length, this.length);
|
||||
var end = start + length - 1;
|
||||
for (var key in thisSet) {
|
||||
if (thisSet.hasOwnProperty(key)) {
|
||||
if (i >= start) {
|
||||
if (i > end) {
|
||||
break;
|
||||
}
|
||||
var item = thisSet[key];
|
||||
newSet[key] = cb.call(context, item, key.substr(PREFIX.length), i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return new OrderedMapImpl(newSet, length);
|
||||
},
|
||||
|
||||
/**
|
||||
* Function filter API. Returns new `OrderedMap`.
|
||||
*
|
||||
* @param {Function} cb Callback to invoke for each item.
|
||||
* @param {Object?=} context Context to invoke callback from.
|
||||
* @return {OrderedMap} OrderedMap that results from filtering.
|
||||
*/
|
||||
filter: function(cb, context) {
|
||||
return this.filterRange(cb, 0, this.length, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* The callback `cb` is invoked with the arguments (item, key,
|
||||
* indexInOriginal).
|
||||
*
|
||||
* @param {Function} cb Returns true if item should be in result.
|
||||
* @param {number} start Start index of filter range.
|
||||
* @param {number} length End index of map range.
|
||||
* @param {*!?} context Context of callback invocation.
|
||||
* @return {OrderedMap} OrderedMap resulting from filtering the range.
|
||||
*/
|
||||
filterRange: function(cb, start, length, context) {
|
||||
var newSet = {};
|
||||
var newSetLength = 0;
|
||||
this.forEachRange(function(item, key, originalIndex) {
|
||||
if (cb.call(context, item, key, originalIndex)) {
|
||||
var normalizedKey = PREFIX + key;
|
||||
newSet[normalizedKey] = item;
|
||||
newSetLength++;
|
||||
}
|
||||
}, start, length);
|
||||
return new OrderedMapImpl(newSet, newSetLength);
|
||||
},
|
||||
|
||||
forEach: function(cb, context) {
|
||||
this.forEachRange(cb, 0, this.length, context);
|
||||
},
|
||||
|
||||
forEachRange: function(cb, start, length, context) {
|
||||
assertValidRangeIndices(start, length, this.length);
|
||||
var thisSet = this._normalizedObj;
|
||||
var i = 0;
|
||||
var end = start + length - 1;
|
||||
for (var key in thisSet) {
|
||||
if (thisSet.hasOwnProperty(key)) {
|
||||
if (i >= start) {
|
||||
if (i > end) {
|
||||
break;
|
||||
}
|
||||
var item = thisSet[key];
|
||||
cb.call(context, item, key.substr(PREFIX.length), i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Even though `mapRange`/`forEachKeyRange` allow zero length mappings, we'll
|
||||
* impose an additional restriction here that the length of mapping be greater
|
||||
* than zero - the only reason is that there are many ways to express length
|
||||
* zero in terms of two keys and that is confusing.
|
||||
*/
|
||||
mapKeyRange: function(cb, startKey, endKey, context) {
|
||||
var startIndex = this.indexOfKey(startKey);
|
||||
var endIndex = this.indexOfKey(endKey);
|
||||
invariant(
|
||||
startIndex !== undefined && endIndex !== undefined,
|
||||
'mapKeyRange must be given keys that are present.'
|
||||
);
|
||||
invariant(
|
||||
endIndex >= startIndex,
|
||||
'OrderedMap.mapKeyRange(...): `endKey` must not come before `startIndex`.'
|
||||
);
|
||||
return this.mapRange(cb, startIndex, (endIndex - startIndex) + 1, context);
|
||||
},
|
||||
|
||||
forEachKeyRange: function(cb, startKey, endKey, context) {
|
||||
var startIndex = this.indexOfKey(startKey);
|
||||
var endIndex = this.indexOfKey(endKey);
|
||||
invariant(
|
||||
startIndex !== undefined && endIndex !== undefined,
|
||||
'forEachKeyRange must be given keys that are present.'
|
||||
);
|
||||
invariant(
|
||||
endIndex >= startIndex,
|
||||
'OrderedMap.forEachKeyRange(...): `endKey` must not come before ' +
|
||||
'`startIndex`.'
|
||||
);
|
||||
this.forEachRange(cb, startIndex, (endIndex - startIndex) + 1, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} pos Index to search for key at.
|
||||
* @return {string|undefined} Either the key at index `pos` or undefined if
|
||||
* not in map.
|
||||
*/
|
||||
keyAtIndex: function(pos) {
|
||||
var computedPositions = this._getOrComputePositions();
|
||||
var keyAtPos = computedPositions.keyByIndex[pos];
|
||||
return keyAtPos ? keyAtPos.substr(PREFIX.length) : undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} key String key from which to find the next key.
|
||||
* @return {string|undefined} Either the next key, or undefined if there is no
|
||||
* next key.
|
||||
* @throws Error if `key` is not in this `OrderedMap`.
|
||||
*/
|
||||
keyAfter: function(key) {
|
||||
return this.nthKeyAfter(key, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} key String key from which to find the preceding key.
|
||||
* @return {string|undefined} Either the preceding key, or undefined if there
|
||||
* is no preceding.key.
|
||||
* @throws Error if `key` is not in this `OrderedMap`.
|
||||
*/
|
||||
keyBefore: function(key) {
|
||||
return this.nthKeyBefore(key, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} key String key from which to find a following key.
|
||||
* @param {number} n Distance to scan forward after `key`.
|
||||
* @return {string|undefined} Either the nth key after `key`, or undefined if
|
||||
* there is no next key.
|
||||
* @throws Error if `key` is not in this `OrderedMap`.
|
||||
*/
|
||||
nthKeyAfter: function(key, n) {
|
||||
var curIndex = this.indexOfKey(key);
|
||||
invariant(
|
||||
curIndex !== undefined,
|
||||
'OrderedMap.nthKeyAfter: The key `%s` does not exist in this instance.',
|
||||
key
|
||||
);
|
||||
return this.keyAtIndex(curIndex + n);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} key String key from which to find a preceding key.
|
||||
* @param {number} n Distance to scan backwards before `key`.
|
||||
* @return {string|undefined} Either the nth key before `key`, or undefined if
|
||||
* there is no previous key.
|
||||
* @throws Error if `key` is not in this `OrderedMap`.
|
||||
*/
|
||||
nthKeyBefore: function(key, n) {
|
||||
return this.nthKeyAfter(key, -n);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} key Key to find the index of.
|
||||
* @return {number|undefined} Index of the provided key, or `undefined` if the
|
||||
* key is not found.
|
||||
*/
|
||||
indexOfKey: function(key) {
|
||||
assertValidPublicKey(key);
|
||||
var normalizedKey = PREFIX + key;
|
||||
var computedPositions = this._getOrComputePositions();
|
||||
var computedPosition = computedPositions.indexByKey[normalizedKey];
|
||||
// Just writing it this way to make it clear this is intentional.
|
||||
return computedPosition === undefined ? undefined : computedPosition;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Array} An ordered array of this object's values.
|
||||
*/
|
||||
toArray: function() {
|
||||
var result = [];
|
||||
var thisSet = this._normalizedObj;
|
||||
for (var key in thisSet) {
|
||||
if (thisSet.hasOwnProperty(key)) {
|
||||
result.push(thisSet[key]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds the key at a given position, or indicates via `undefined` that that
|
||||
* position does not exist in the `OrderedMap`. It is appropriate to return
|
||||
* undefined, indicating that the key doesn't exist in the `OrderedMap`
|
||||
* because `undefined` is not ever a valid `OrderedMap` key.
|
||||
*
|
||||
* @private
|
||||
* @return {string?} Name of the item at position `pos`, or `undefined` if
|
||||
* there is no item at that position.
|
||||
*/
|
||||
_getOrComputePositions: function() {
|
||||
// TODO: Entertain computing this at construction time in some less
|
||||
// performance critical paths.
|
||||
var computedPositions = this._computedPositions;
|
||||
if (!computedPositions) {
|
||||
this._computePositions();
|
||||
}
|
||||
return this._computedPositions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Precomputes the index/key mapping for future lookup. Since `OrderedMap`s
|
||||
* are immutable, there is only ever a need to perform this once.
|
||||
* @private
|
||||
*/
|
||||
_computePositions: function() {
|
||||
this._computedPositions = {
|
||||
keyByIndex: {},
|
||||
indexByKey: {},
|
||||
};
|
||||
var keyByIndex = this._computedPositions.keyByIndex;
|
||||
var indexByKey = this._computedPositions.indexByKey;
|
||||
var index = 0;
|
||||
var thisSet = this._normalizedObj;
|
||||
for (var key in thisSet) {
|
||||
if (thisSet.hasOwnProperty(key)) {
|
||||
keyByIndex[index] = key;
|
||||
indexByKey[key] = index;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Object.assign(OrderedMapImpl.prototype, OrderedMapMethods);
|
||||
|
||||
var OrderedMap = {
|
||||
from: function(orderedMap) {
|
||||
invariant(
|
||||
orderedMap instanceof OrderedMapImpl,
|
||||
'OrderedMap.from(...): Expected an OrderedMap instance.'
|
||||
);
|
||||
return _fromNormalizedObjects(orderedMap._normalizedObj, null);
|
||||
},
|
||||
|
||||
fromArray: function(arr, keyExtractor) {
|
||||
invariant(
|
||||
Array.isArray(arr),
|
||||
'OrderedMap.fromArray(...): First argument must be an array.'
|
||||
);
|
||||
invariant(
|
||||
typeof keyExtractor === 'function',
|
||||
'OrderedMap.fromArray(...): Second argument must be a function used ' +
|
||||
'to determine the unique key for each entry.'
|
||||
);
|
||||
return new OrderedMapImpl(
|
||||
extractObjectFromArray(arr, keyExtractor),
|
||||
arr.length
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = OrderedMap;
|
||||
@@ -1,107 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactPropTransferer
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var emptyFunction = require('emptyFunction');
|
||||
var joinClasses = require('joinClasses');
|
||||
|
||||
/**
|
||||
* Creates a transfer strategy that will merge prop values using the supplied
|
||||
* `mergeStrategy`. If a prop was previously unset, this just sets it.
|
||||
*
|
||||
* @param {function} mergeStrategy
|
||||
* @return {function}
|
||||
*/
|
||||
function createTransferStrategy(mergeStrategy) {
|
||||
return function(props, key, value) {
|
||||
if (!props.hasOwnProperty(key)) {
|
||||
props[key] = value;
|
||||
} else {
|
||||
props[key] = mergeStrategy(props[key], value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var transferStrategyMerge = createTransferStrategy(function(a, b) {
|
||||
// `merge` overrides the first object's (`props[key]` above) keys using the
|
||||
// second object's (`value`) keys. An object's style's existing `propA` would
|
||||
// get overridden. Flip the order here.
|
||||
return Object.assign({}, b, a);
|
||||
});
|
||||
|
||||
/**
|
||||
* Transfer strategies dictate how props are transferred by `transferPropsTo`.
|
||||
* NOTE: if you add any more exceptions to this list you should be sure to
|
||||
* update `cloneWithProps()` accordingly.
|
||||
*/
|
||||
var TransferStrategies = {
|
||||
/**
|
||||
* Never transfer `children`.
|
||||
*/
|
||||
children: emptyFunction,
|
||||
/**
|
||||
* Transfer the `className` prop by merging them.
|
||||
*/
|
||||
className: createTransferStrategy(joinClasses),
|
||||
/**
|
||||
* Transfer the `style` prop (which is an object) by merging them.
|
||||
*/
|
||||
style: transferStrategyMerge,
|
||||
};
|
||||
|
||||
/**
|
||||
* Mutates the first argument by transferring the properties from the second
|
||||
* argument.
|
||||
*
|
||||
* @param {object} props
|
||||
* @param {object} newProps
|
||||
* @return {object}
|
||||
*/
|
||||
function transferInto(props, newProps) {
|
||||
for (var thisKey in newProps) {
|
||||
if (!newProps.hasOwnProperty(thisKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var transferStrategy = TransferStrategies[thisKey];
|
||||
|
||||
if (transferStrategy && TransferStrategies.hasOwnProperty(thisKey)) {
|
||||
transferStrategy(props, thisKey, newProps[thisKey]);
|
||||
} else if (!props.hasOwnProperty(thisKey)) {
|
||||
props[thisKey] = newProps[thisKey];
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* ReactPropTransferer are capable of transferring props to another component
|
||||
* using a `transferPropsTo` method.
|
||||
*
|
||||
* @class ReactPropTransferer
|
||||
*/
|
||||
var ReactPropTransferer = {
|
||||
|
||||
/**
|
||||
* Merge two props objects using TransferStrategies.
|
||||
*
|
||||
* @param {object} oldProps original props (they take precedence)
|
||||
* @param {object} newProps new props to merge in
|
||||
* @return {object} a new object containing both sets of props merged.
|
||||
*/
|
||||
mergeProps: function(oldProps, newProps) {
|
||||
return transferInto(Object.assign({}, oldProps), newProps);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactPropTransferer;
|
||||
@@ -1,941 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var OrderedMap;
|
||||
|
||||
/**
|
||||
* Shared, reusable objects.
|
||||
*/
|
||||
var hasEmptyStringKey = {
|
||||
'thisKeyIsFine': {data: []},
|
||||
'': {thisShouldCauseAFailure: []},
|
||||
'thisKeyIsAlsoFine': {data: []},
|
||||
};
|
||||
|
||||
/**
|
||||
* Used as map/forEach callback.
|
||||
*/
|
||||
var duplicate = function(itm, key, count) {
|
||||
return {
|
||||
uniqueID: itm.uniqueID,
|
||||
val: itm.val + key + count + this.justToTestScope,
|
||||
};
|
||||
};
|
||||
|
||||
// Should not be allowed - because then null/'null' become impossible to
|
||||
// distinguish. Every key MUST be a string period!
|
||||
var hasNullAndUndefStringKey = [
|
||||
{uniqueID: 'undefined', val: 'thisIsUndefined'},
|
||||
{uniqueID: 'null', val: 'thisIsNull'},
|
||||
];
|
||||
var hasNullKey = [
|
||||
{uniqueID: 'thisKeyIsFine', data: []},
|
||||
{uniqueID: 'thisKeyIsAlsoFine', data: []},
|
||||
{uniqueID: null, data: []},
|
||||
];
|
||||
|
||||
var hasObjectKey = [
|
||||
{uniqueID: 'thisKeyIsFine', data: []},
|
||||
{uniqueID: 'thisKeyIsAlsoFine', data: []},
|
||||
{uniqueID: {}, data: []},
|
||||
];
|
||||
|
||||
var hasArrayKey = [
|
||||
{uniqueID: 'thisKeyIsFine', data: []},
|
||||
{uniqueID: 'thisKeyIsAlsoFine', data: []},
|
||||
{uniqueID: [], data: []},
|
||||
];
|
||||
|
||||
// This should be allowed
|
||||
var hasNullStringKey = [
|
||||
{uniqueID: 'thisKeyIsFine', data: []},
|
||||
{uniqueID: 'thisKeyIsAlsoFine', data: []},
|
||||
{uniqueID: 'null', data: []},
|
||||
];
|
||||
|
||||
var hasUndefinedKey = [
|
||||
{uniqueID: 'thisKeyIsFine', data: []},
|
||||
{uniqueID: 'thisKeyIsAlsoFine', data: []},
|
||||
{uniqueID: undefined, data: []},
|
||||
];
|
||||
|
||||
var hasUndefinedStringKey = [
|
||||
{uniqueID: 'thisKeyIsFine', data: []},
|
||||
{uniqueID: 'thisKeyIsAlsoFine', data: []},
|
||||
{uniqueID: 'undefined', data: []},
|
||||
];
|
||||
|
||||
var hasPositiveNumericKey = [
|
||||
{uniqueID: 'notANumber', data: []},
|
||||
{uniqueID: '5', data: []},
|
||||
{uniqueID: 'notAnotherNumber', data: []},
|
||||
];
|
||||
|
||||
var hasZeroStringKey = [
|
||||
{uniqueID: 'greg', data: 'grego'},
|
||||
{uniqueID: '0', data: '0o'},
|
||||
{uniqueID: 'tom', data: 'tomo'},
|
||||
];
|
||||
|
||||
var hasZeroNumberKey = [
|
||||
{uniqueID: 'greg', data: 'grego'},
|
||||
{uniqueID: 0, data: '0o'},
|
||||
{uniqueID: 'tom', data: 'tomo'},
|
||||
];
|
||||
|
||||
var hasAllNumericStringKeys = [
|
||||
{uniqueID: '0', name: 'Gregory'},
|
||||
{uniqueID: '2', name: 'James'},
|
||||
{uniqueID: '1', name: 'Tom'},
|
||||
];
|
||||
|
||||
var hasAllNumericKeys = [
|
||||
{uniqueID: 0, name: 'Gregory'},
|
||||
{uniqueID: 2, name: 'James'},
|
||||
{uniqueID: 1, name: 'Tom'},
|
||||
];
|
||||
|
||||
var hasAllValidKeys = [
|
||||
{uniqueID: 'keyOne', value: 'valueOne'},
|
||||
{uniqueID: 'keyTwo', value: 'valueTwo'},
|
||||
];
|
||||
|
||||
var hasDuplicateKeys = [
|
||||
{uniqueID: 'keyOne', value: 'valueOne'},
|
||||
{uniqueID: 'keyTwo', value: 'valueTwo'},
|
||||
{uniqueID: 'keyOne', value: 'valueThree'},
|
||||
];
|
||||
|
||||
var idEntities = [
|
||||
{uniqueID: 'greg', name: 'Gregory'},
|
||||
{uniqueID: 'james', name: 'James'},
|
||||
{uniqueID: 'tom', name: 'Tom'},
|
||||
];
|
||||
|
||||
var hasEmptyKey = [
|
||||
{uniqueID: 'greg', name: 'Gregory'},
|
||||
{uniqueID: '', name: 'James'},
|
||||
{uniqueID: 'tom', name: 'Tom'},
|
||||
];
|
||||
|
||||
var extractUniqueID = function(entity) {
|
||||
return entity.uniqueID;
|
||||
};
|
||||
|
||||
describe('OrderedMap', function() {
|
||||
beforeEach(function() {
|
||||
jest.resetModuleRegistry();
|
||||
OrderedMap = require('OrderedMap');
|
||||
});
|
||||
|
||||
it('should create according to simple object with keys', function() {
|
||||
OrderedMap.fromArray(hasAllValidKeys, extractUniqueID);
|
||||
// Iterate over and ensure key order.
|
||||
});
|
||||
|
||||
it('should create from array when providing an identity CB', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(idEntities, extractUniqueID);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw if constructing from Array without identity CB', function() {
|
||||
OrderedMap.fromArray(idEntities, extractUniqueID);
|
||||
// Iterate and ensure key order
|
||||
});
|
||||
|
||||
it('should not throw when fromArray extracts a numeric key', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasPositiveNumericKey, extractUniqueID);
|
||||
}).not.toThrow();
|
||||
|
||||
});
|
||||
|
||||
it('should throw when any key is the empty string', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasEmptyKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should not throw when a key is the string "undefined" or "null"',
|
||||
function() {
|
||||
var om = OrderedMap.fromArray(hasNullAndUndefStringKey, extractUniqueID);
|
||||
expect(om.length).toBe(2);
|
||||
expect(om.indexOfKey('undefined')).toBe(0);
|
||||
expect(om.indexOfKey('null')).toBe(1);
|
||||
expect(om.keyAfter('undefined')).toBe('null');
|
||||
expect(om.keyAfter('null')).toBe(undefined);
|
||||
expect(om.keyBefore('undefined')).toBe(undefined);
|
||||
expect(om.has('undefined')).toBe(true);
|
||||
expect(om.has('null')).toBe(true);
|
||||
expect(om.get('undefined').val).toBe('thisIsUndefined');
|
||||
expect(om.get('null').val).toBe('thisIsNull');
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Numeric keys are cast to strings.
|
||||
*/
|
||||
it('should not throw when a key is the number zero', function() {
|
||||
var om = OrderedMap.fromArray(hasZeroNumberKey, extractUniqueID);
|
||||
expect(om.length).toBe(3);
|
||||
expect(om.indexOfKey('0')).toBe(1);
|
||||
expect(om.indexOfKey(0)).toBe(1);
|
||||
});
|
||||
|
||||
it('should throw when any key is falsey', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasEmptyStringKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasNullKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasUndefinedKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should not throw on string keys "undefined/null"', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasNullStringKey, extractUniqueID);
|
||||
}).not.toThrow();
|
||||
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasUndefinedStringKey, extractUniqueID);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw on extracting keys that are not strings/nums', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasObjectKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasArrayKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should throw if instantiating with duplicate key', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasDuplicateKeys, extractUniqueID);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should not throw when a key is the string "0"', function() {
|
||||
var verifyOM = function(om) {
|
||||
expect(om.length).toBe(3);
|
||||
expect(om.indexOfKey('greg')).toBe(0);
|
||||
expect(om.indexOfKey('0')).toBe(1);
|
||||
expect(om.indexOfKey(0)).toBe(1); // Casts on writes and reads.
|
||||
expect(om.indexOfKey('tom')).toBe(2);
|
||||
expect(om.keyAfter('greg')).toBe('0');
|
||||
expect(om.keyAfter('0')).toBe('tom');
|
||||
expect(om.keyAfter(0)).toBe('tom');
|
||||
expect(om.keyAfter('tom')).toBe(undefined);
|
||||
expect(om.keyBefore('greg')).toBe(undefined);
|
||||
expect(om.keyBefore(0)).toBe('greg');
|
||||
expect(om.keyBefore('0')).toBe('greg');
|
||||
expect(om.keyBefore('tom')).toBe('0');
|
||||
expect(om.has('undefined')).toBe(false);
|
||||
expect(om.has(0)).toBe(true);
|
||||
expect(om.has('0')).toBe(true);
|
||||
};
|
||||
verifyOM(OrderedMap.fromArray(hasZeroStringKey, extractUniqueID));
|
||||
verifyOM(OrderedMap.fromArray(hasZeroNumberKey, extractUniqueID));
|
||||
});
|
||||
|
||||
it('should throw when getting invalid public key', function() {
|
||||
var om = OrderedMap.fromArray(hasAllValidKeys, extractUniqueID);
|
||||
expect(function() {
|
||||
om.has(undefined);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.get(undefined);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.has(null);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.get(null);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.has('');
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.get('');
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should throw when any key is falsey', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasEmptyStringKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasNullKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(hasUndefinedKey, extractUniqueID);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
|
||||
it('should throw when fromArray is passed crazy args', function() {
|
||||
// Test passing another OrderedMap (when it expects a plain object.)
|
||||
// This is probably not what you meant to do! We should error.
|
||||
var validOM = OrderedMap.fromArray(hasAllValidKeys, extractUniqueID);
|
||||
expect(function() {
|
||||
OrderedMap.fromArray({uniqueID: 'asdf'}, extractUniqueID);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(validOM, extractUniqueID);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should throw when fromArray is passed crazy things', function() {
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(null, extractUniqueID);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
OrderedMap.fromArray('stringgg', extractUniqueID);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(undefined, extractUniqueID);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(new Date(), extractUniqueID);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
OrderedMap.fromArray({}, extractUniqueID);
|
||||
}).toThrow();
|
||||
|
||||
// Test failure without extractor
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(idEntities);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(idEntities, extractUniqueID);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
// Testing methods that accept other `OrderedMap`s.
|
||||
it('should throw when from/merge is passed an non-OrderedMap.', function() {
|
||||
// Test passing an array to construction.
|
||||
expect(function() {
|
||||
OrderedMap.from(idEntities, extractUniqueID);
|
||||
}).toThrow();
|
||||
|
||||
// Test passing an array to merge.
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(idEntities, extractUniqueID)
|
||||
.merge(idEntities, extractUniqueID);
|
||||
}).toThrow();
|
||||
|
||||
|
||||
// Test passing a plain object to merge.
|
||||
expect(function() {
|
||||
OrderedMap.fromArray(
|
||||
idEntities,
|
||||
extractUniqueID
|
||||
).merge({blah: 'willFail'});
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should throw when accessing key before/after of non-key', function() {
|
||||
var om = OrderedMap.fromArray(
|
||||
[
|
||||
{uniqueID: 'first'},
|
||||
{uniqueID: 'two'},
|
||||
], extractUniqueID
|
||||
);
|
||||
expect(function() {
|
||||
om.keyBefore('dog');
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyAfter('cat');
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyAfter(null);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyAfter(undefined);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should throw passing invalid/not-present-keys to before/after',
|
||||
function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'one', val: 'first'},
|
||||
{uniqueID: 'two', val: 'second'},
|
||||
{uniqueID: 'three', val: 'third'},
|
||||
{uniqueID: 'four', val: 'fourth'},
|
||||
], extractUniqueID);
|
||||
|
||||
expect(function() {
|
||||
om.keyBefore('');
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyBefore(null);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyBefore(undefined);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyBefore('notInTheOrderedMap!');
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
om.keyAfter('');
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyAfter(null);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyAfter(undefined);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.keyAfter('notInTheOrderedMap!');
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
om.nthKeyAfter('', 1);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.nthKeyAfter(null, 1);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.nthKeyAfter(undefined, 1);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.nthKeyAfter('notInTheOrderedMap!', 1);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
om.nthKeyBefore('', 1);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.nthKeyBefore(null, 1);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.nthKeyBefore(undefined, 1);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.nthKeyBefore('notInTheOrderedMap!', 1);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should correctly determine the nth key after before', function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'one', val: 'first'},
|
||||
{uniqueID: 'two', val: 'second'},
|
||||
{uniqueID: 'three', val: 'third'},
|
||||
{uniqueID: 'four', val: 'fourth'},
|
||||
], extractUniqueID);
|
||||
expect(om.keyBefore('one')).toBe(undefined); // first key
|
||||
expect(om.keyBefore('two')).toBe('one');
|
||||
expect(om.keyBefore('three')).toBe('two');
|
||||
expect(om.keyBefore('four')).toBe('three');
|
||||
|
||||
expect(om.keyAfter('one')).toBe('two'); // first key
|
||||
expect(om.keyAfter('two')).toBe('three');
|
||||
expect(om.keyAfter('three')).toBe('four');
|
||||
expect(om.keyAfter('four')).toBe(undefined);
|
||||
|
||||
expect(om.nthKeyBefore('one', 0)).toBe('one'); // first key
|
||||
expect(om.nthKeyBefore('one', 1)).toBe(undefined);
|
||||
expect(om.nthKeyBefore('one', 2)).toBe(undefined);
|
||||
expect(om.nthKeyBefore('two', 0)).toBe('two');
|
||||
expect(om.nthKeyBefore('two', 1)).toBe('one');
|
||||
expect(om.nthKeyBefore('four', 0)).toBe('four');
|
||||
expect(om.nthKeyBefore('four', 1)).toBe('three');
|
||||
|
||||
expect(om.nthKeyAfter('one', 0)).toBe('one');
|
||||
expect(om.nthKeyAfter('one', 1)).toBe('two');
|
||||
expect(om.nthKeyAfter('one', 2)).toBe('three');
|
||||
expect(om.nthKeyAfter('two', 0)).toBe('two');
|
||||
expect(om.nthKeyAfter('two', 1)).toBe('three');
|
||||
expect(om.nthKeyAfter('four', 0)).toBe('four');
|
||||
expect(om.nthKeyAfter('four', 1)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should compute key indices correctly', function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'one', val: 'first'},
|
||||
{uniqueID: 'two', val: 'second'},
|
||||
], extractUniqueID);
|
||||
expect(om.keyAtIndex(0)).toBe('one');
|
||||
expect(om.keyAtIndex(1)).toBe('two');
|
||||
expect(om.keyAtIndex(2)).toBe(undefined);
|
||||
expect(om.indexOfKey('one')).toBe(0);
|
||||
expect(om.indexOfKey('two')).toBe(1);
|
||||
expect(om.indexOfKey('nope')).toBe(undefined);
|
||||
expect(function() {
|
||||
om.indexOfKey(null);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.indexOfKey(undefined);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.indexOfKey(''); // Empty key is not allowed
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should compute indices on array that extracted numeric ids', function() {
|
||||
var som = OrderedMap.fromArray(hasZeroStringKey, extractUniqueID);
|
||||
expect(som.keyAtIndex(0)).toBe('greg');
|
||||
expect(som.keyAtIndex(1)).toBe('0');
|
||||
expect(som.keyAtIndex(2)).toBe('tom');
|
||||
expect(som.indexOfKey('greg')).toBe(0);
|
||||
expect(som.indexOfKey('0')).toBe(1);
|
||||
expect(som.indexOfKey('tom')).toBe(2);
|
||||
|
||||
|
||||
var verifyNumericKeys = function(nom) {
|
||||
expect(nom.keyAtIndex(0)).toBe('0');
|
||||
expect(nom.keyAtIndex(1)).toBe('2');
|
||||
expect(nom.keyAtIndex(2)).toBe('1');
|
||||
expect(nom.indexOfKey('0')).toBe(0);
|
||||
expect(nom.indexOfKey('2')).toBe(1); // Prove these are not ordered by
|
||||
expect(nom.indexOfKey('1')).toBe(2); // their keys
|
||||
};
|
||||
var omStringNumberKeys =
|
||||
OrderedMap.fromArray(hasAllNumericStringKeys, extractUniqueID);
|
||||
verifyNumericKeys(omStringNumberKeys);
|
||||
var omNumericKeys =
|
||||
OrderedMap.fromArray(hasAllNumericKeys, extractUniqueID);
|
||||
verifyNumericKeys(omNumericKeys);
|
||||
});
|
||||
|
||||
it('should compute indices on mutually exclusive merge', function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'one', val: 'first'},
|
||||
{uniqueID: 'two', val: 'second'},
|
||||
], extractUniqueID);
|
||||
var om2 = OrderedMap.fromArray([
|
||||
{uniqueID: 'three', val: 'third'},
|
||||
], extractUniqueID);
|
||||
var res = om.merge(om2);
|
||||
|
||||
expect(res.length).toBe(3);
|
||||
|
||||
expect(res.keyAtIndex(0)).toBe('one');
|
||||
expect(res.keyAtIndex(1)).toBe('two');
|
||||
expect(res.keyAtIndex(2)).toBe('three');
|
||||
expect(res.keyAtIndex(3)).toBe(undefined);
|
||||
|
||||
expect(res.indexOfKey('one')).toBe(0);
|
||||
expect(res.indexOfKey('two')).toBe(1);
|
||||
expect(res.indexOfKey('three')).toBe(2);
|
||||
expect(res.indexOfKey('dog')).toBe(undefined);
|
||||
|
||||
expect(res.has('one')).toBe(true);
|
||||
expect(res.has('two')).toBe(true);
|
||||
expect(res.has('three')).toBe(true);
|
||||
expect(res.has('dog')).toBe(false);
|
||||
|
||||
expect(res.get('one').val).toBe('first');
|
||||
expect(res.get('two').val).toBe('second');
|
||||
expect(res.get('three').val).toBe('third');
|
||||
expect(res.get('dog')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should compute indices on intersected merge', function() {
|
||||
var oneTwo = OrderedMap.fromArray([
|
||||
{uniqueID: 'one', val: 'first'},
|
||||
{uniqueID: 'two', val: 'secondOM1'},
|
||||
], extractUniqueID);
|
||||
|
||||
var testOneTwoMergedWithTwoThree = function(res) {
|
||||
expect(res.length).toBe(3);
|
||||
expect(res.keyAtIndex(0)).toBe('one');
|
||||
expect(res.keyAtIndex(1)).toBe('two');
|
||||
expect(res.keyAtIndex(2)).toBe('three');
|
||||
expect(res.keyAtIndex(3)).toBe(undefined);
|
||||
expect(res.indexOfKey('one')).toBe(0);
|
||||
expect(res.indexOfKey('two')).toBe(1);
|
||||
expect(res.indexOfKey('three')).toBe(2);
|
||||
expect(res.indexOfKey('dog')).toBe(undefined);
|
||||
expect(res.has('one')).toBe(true);
|
||||
expect(res.has('two')).toBe(true);
|
||||
expect(res.has('three')).toBe(true);
|
||||
expect(res.has('dog')).toBe(false);
|
||||
expect(res.get('one').val).toBe('first');
|
||||
expect(res.get('two').val).toBe('secondOM2');
|
||||
expect(res.get('three').val).toBe('third');
|
||||
expect(res.get('dog')).toBe(undefined);
|
||||
};
|
||||
|
||||
var result =
|
||||
oneTwo.merge(OrderedMap.fromArray([
|
||||
{uniqueID: 'two', val: 'secondOM2'},
|
||||
{uniqueID: 'three', val: 'third'},
|
||||
], extractUniqueID));
|
||||
testOneTwoMergedWithTwoThree(result);
|
||||
|
||||
// Everything should be exactly as before, since the ordering of `two` was
|
||||
// already determined by `om`.
|
||||
result = oneTwo.merge(
|
||||
OrderedMap.fromArray([
|
||||
{uniqueID: 'three', val: 'third'},
|
||||
{uniqueID: 'two', val:'secondOM2'},
|
||||
], extractUniqueID)
|
||||
);
|
||||
testOneTwoMergedWithTwoThree(result);
|
||||
|
||||
|
||||
var testTwoThreeMergedWithOneTwo = function(res) {
|
||||
expect(res.length).toBe(3);
|
||||
expect(res.keyAtIndex(0)).toBe('two');
|
||||
expect(res.keyAtIndex(1)).toBe('three');
|
||||
expect(res.keyAtIndex(2)).toBe('one');
|
||||
expect(res.keyAtIndex(3)).toBe(undefined);
|
||||
expect(res.indexOfKey('two')).toBe(0);
|
||||
expect(res.indexOfKey('three')).toBe(1);
|
||||
expect(res.indexOfKey('one')).toBe(2);
|
||||
expect(res.indexOfKey('cat')).toBe(undefined);
|
||||
expect(res.has('two')).toBe(true);
|
||||
expect(res.has('three')).toBe(true);
|
||||
expect(res.has('one')).toBe(true);
|
||||
expect(res.has('dog')).toBe(false);
|
||||
expect(res.get('one').val).toBe('first');
|
||||
expect(res.get('two').val).toBe('secondOM1');
|
||||
expect(res.get('three').val).toBe('third');
|
||||
expect(res.get('dog')).toBe(undefined);
|
||||
};
|
||||
result = OrderedMap.fromArray([
|
||||
{uniqueID: 'two', val: 'secondOM2'},
|
||||
{uniqueID: 'three', val: 'third'},
|
||||
], extractUniqueID).merge(oneTwo);
|
||||
testTwoThreeMergedWithOneTwo(result);
|
||||
|
||||
});
|
||||
|
||||
it('should merge mutually exclusive keys to the end.', function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'one', val: 'first'},
|
||||
{uniqueID: 'two', val: 'second'},
|
||||
], extractUniqueID);
|
||||
var om2 = OrderedMap.fromArray([
|
||||
{uniqueID: 'three', val: 'first'},
|
||||
{uniqueID: 'four', val: 'second'},
|
||||
], extractUniqueID);
|
||||
var res = om.merge(om2);
|
||||
expect(res.length).toBe(4);
|
||||
|
||||
});
|
||||
|
||||
it('should map correctly', function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'x', val: 'xx'},
|
||||
{uniqueID: 'y', val: 'yy'},
|
||||
{uniqueID: 'z', val: 'zz'},
|
||||
], extractUniqueID);
|
||||
var scope = {justToTestScope: 'justTestingScope'};
|
||||
var verifyResult = function(omResult) {
|
||||
expect(omResult.length).toBe(3);
|
||||
expect(omResult.keyAtIndex(0)).toBe('x');
|
||||
expect(omResult.keyAtIndex(1)).toBe('y');
|
||||
expect(omResult.keyAtIndex(2)).toBe('z');
|
||||
expect(omResult.get('x').val).toBe('xxx0justTestingScope');
|
||||
expect(omResult.get('y').val).toBe('yyy1justTestingScope');
|
||||
expect(omResult.get('z').val).toBe('zzz2justTestingScope');
|
||||
};
|
||||
var resultOM = om.map(function(itm, key, count) {
|
||||
return {
|
||||
uniqueID: itm.uniqueID,
|
||||
val: itm.val + key + count + this.justToTestScope,
|
||||
};
|
||||
}, scope);
|
||||
verifyResult(resultOM);
|
||||
|
||||
var resArray = [];
|
||||
om.forEach(function(itm, key, count) {
|
||||
resArray.push({
|
||||
uniqueID: itm.uniqueID,
|
||||
val: itm.val + key + count + this.justToTestScope,
|
||||
});
|
||||
}, scope);
|
||||
resultOM = OrderedMap.fromArray(resArray, extractUniqueID);
|
||||
verifyResult(resultOM);
|
||||
});
|
||||
|
||||
it('should filter correctly', function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'x', val: 'xx'},
|
||||
{uniqueID: 'y', val: 'yy'},
|
||||
{uniqueID: 'z', val: 'zz'},
|
||||
], extractUniqueID);
|
||||
var scope = {justToTestScope: 'justTestingScope'};
|
||||
|
||||
var filteringCallback = function(item, key, indexInOriginal) {
|
||||
expect(this).toBe(scope);
|
||||
expect(key === 'x' || key === 'y' || key === 'z').toBe(true);
|
||||
if (key === 'x') {
|
||||
expect(item.val).toBe('xx');
|
||||
expect(indexInOriginal).toBe(0);
|
||||
return false;
|
||||
} else if (key === 'y') {
|
||||
expect(item.val).toBe('yy');
|
||||
expect(indexInOriginal).toBe(1);
|
||||
return true;
|
||||
} else {
|
||||
expect(item.val).toBe('zz');
|
||||
expect(indexInOriginal).toBe(2);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var verifyResult = function(omResult) {
|
||||
expect(omResult.length).toBe(2);
|
||||
expect(omResult.keyAtIndex(0)).toBe('y');
|
||||
expect(omResult.keyAtIndex(1)).toBe('z');
|
||||
expect(omResult.has('x')).toBe(false);
|
||||
expect(omResult.has('z')).toBe(true);
|
||||
expect(omResult.get('z').val).toBe('zz');
|
||||
expect(omResult.has('y')).toBe(true);
|
||||
expect(omResult.get('y').val).toBe('yy');
|
||||
};
|
||||
|
||||
var resultOM = om.filter(filteringCallback, scope);
|
||||
verifyResult(resultOM);
|
||||
});
|
||||
|
||||
it('should throw when providing invalid ranges to ranging', function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'x', val: 'xx'},
|
||||
{uniqueID: 'y', val: 'yy'},
|
||||
{uniqueID: 'z', val: 'zz'},
|
||||
], extractUniqueID);
|
||||
var scope = {justToTestScope: 'justTestingScope'};
|
||||
|
||||
expect(function() {
|
||||
om.mapRange(duplicate, 0, 3, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.filterRange(duplicate, 0, 3, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.forEachRange(duplicate, 0, 3, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.mapKeyRange(duplicate, 'x', 3, scope);
|
||||
}).toThrow(
|
||||
'mapKeyRange must be given keys that are present.'
|
||||
);
|
||||
expect(function() {
|
||||
om.forEachKeyRange(duplicate, 'x', 3, scope);
|
||||
}).toThrow(
|
||||
'forEachKeyRange must be given keys that are present.'
|
||||
);
|
||||
|
||||
expect(function() {
|
||||
om.mapRange(duplicate, 0, 4, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.filterRange(duplicate, 0, 4, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachRange(duplicate, 0, 4, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.mapKeyRange(duplicate, 'x', null, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachKeyRange(duplicate, 'x', null, scope);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
om.mapRange(duplicate, -1, 1, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.filterRange(duplicate, -1, 1, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachRange(duplicate, -1, 1, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.mapKeyRange(duplicate, null, 'y', scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachKeyRange(duplicate, null, 'y', scope);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
om.mapRange(duplicate, 0, 0, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.filterRange(duplicate, 0, 0, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.forEachRange(duplicate, 0, 0, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.mapKeyRange(duplicate, 'x', 'x', scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.forEachKeyRange(duplicate, 'x', 'x', scope);
|
||||
}).not.toThrow();
|
||||
|
||||
expect(function() {
|
||||
om.mapRange(duplicate, 0, -1, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.filterRange(duplicate, 0, -1, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachRange(duplicate, 0, -1, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.mapKeyRange(duplicate, 'x', null, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachKeyRange(duplicate, 'x', null, scope);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
om.mapRange(duplicate, 2, 1, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.filterRange(duplicate, 2, 1, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.forEachRange(duplicate, 2, 1, scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.mapKeyRange(duplicate, 'z', 'z', scope);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
om.forEachKeyRange(duplicate, 'z', 'z', scope);
|
||||
}).not.toThrow();
|
||||
|
||||
expect(function() {
|
||||
om.mapRange(duplicate, 2, 2, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.filterRange(duplicate, 2, 2, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachRange(duplicate, 2, 2, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.mapKeyRange(duplicate, 'z', null, scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachKeyRange(duplicate, 'z', null, scope);
|
||||
}).toThrow();
|
||||
|
||||
// Provide keys in reverse order - should throw.
|
||||
expect(function() {
|
||||
om.mapKeyRange(duplicate, 'y', 'x', scope);
|
||||
}).toThrow();
|
||||
expect(function() {
|
||||
om.forEachKeyRange(duplicate, 'y', 'x', scope);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
// TEST length zero map, or keyrange start===end
|
||||
|
||||
it('should map range correctly', function() {
|
||||
var om = OrderedMap.fromArray([
|
||||
{uniqueID: 'x', val: 'xx'},
|
||||
{uniqueID: 'y', val: 'yy'},
|
||||
{uniqueID: 'z', val: 'zz'},
|
||||
], extractUniqueID);
|
||||
var scope = {justToTestScope: 'justTestingScope'};
|
||||
var verifyThreeItems = function(omResult) {
|
||||
expect(omResult.length).toBe(3);
|
||||
expect(omResult.keyAtIndex(0)).toBe('x');
|
||||
expect(omResult.keyAtIndex(1)).toBe('y');
|
||||
expect(omResult.keyAtIndex(2)).toBe('z');
|
||||
expect(omResult.get('x').val).toBe('xxx0justTestingScope');
|
||||
expect(omResult.get('y').val).toBe('yyy1justTestingScope');
|
||||
expect(omResult.get('z').val).toBe('zzz2justTestingScope');
|
||||
};
|
||||
var verifyFirstTwoItems = function(omResult) {
|
||||
expect(omResult.length).toBe(2);
|
||||
expect(omResult.keyAtIndex(0)).toBe('x');
|
||||
expect(omResult.keyAtIndex(1)).toBe('y');
|
||||
expect(omResult.get('x').val).toBe('xxx0justTestingScope');
|
||||
expect(omResult.get('y').val).toBe('yyy1justTestingScope');
|
||||
};
|
||||
|
||||
var verifyLastTwoItems = function(omResult) {
|
||||
expect(omResult.length).toBe(2);
|
||||
expect(omResult.keyAtIndex(0)).toBe('y');
|
||||
expect(omResult.keyAtIndex(1)).toBe('z');
|
||||
expect(omResult.get('y').val).toBe('yyy1justTestingScope');
|
||||
expect(omResult.get('z').val).toBe('zzz2justTestingScope');
|
||||
};
|
||||
|
||||
var verifyMiddleItem = function(omResult) {
|
||||
expect(omResult.length).toBe(1);
|
||||
expect(omResult.keyAtIndex(0)).toBe('y');
|
||||
expect(omResult.get('y').val).toBe('yyy1justTestingScope');
|
||||
};
|
||||
|
||||
var verifyEmpty = function(omResult) {
|
||||
expect(omResult.length).toBe(0);
|
||||
};
|
||||
|
||||
var omResultThree = om.mapRange(duplicate, 0, 3, scope);
|
||||
verifyThreeItems(omResultThree);
|
||||
var resArray = [];
|
||||
var pushToResArray = function(itm, key, count) {
|
||||
resArray.push({
|
||||
uniqueID: itm.uniqueID,
|
||||
val: itm.val + key + count + this.justToTestScope,
|
||||
});
|
||||
};
|
||||
|
||||
om.forEachRange(pushToResArray, 0, 3, scope);
|
||||
omResultThree = OrderedMap.fromArray(resArray, extractUniqueID);
|
||||
verifyThreeItems(omResultThree);
|
||||
|
||||
var omResultFirstTwo = om.mapRange(duplicate, 0, 2, scope);
|
||||
verifyFirstTwoItems(omResultFirstTwo);
|
||||
resArray = [];
|
||||
om.forEachRange(pushToResArray, 0, 2, scope);
|
||||
omResultFirstTwo = OrderedMap.fromArray(resArray, extractUniqueID);
|
||||
verifyFirstTwoItems(omResultFirstTwo);
|
||||
|
||||
var omResultLastTwo = om.mapRange(duplicate, 1, 2, scope);
|
||||
verifyLastTwoItems(omResultLastTwo);
|
||||
resArray = [];
|
||||
om.forEachRange(pushToResArray, 1, 2, scope);
|
||||
omResultLastTwo = OrderedMap.fromArray(resArray, extractUniqueID);
|
||||
verifyLastTwoItems(omResultLastTwo);
|
||||
|
||||
var omResultMiddle = om.mapRange(duplicate, 1, 1, scope);
|
||||
verifyMiddleItem(omResultMiddle);
|
||||
resArray = [];
|
||||
om.forEachRange(pushToResArray, 1, 1, scope);
|
||||
omResultMiddle = OrderedMap.fromArray(resArray, extractUniqueID);
|
||||
verifyMiddleItem(omResultMiddle);
|
||||
|
||||
var omResultNone = om.mapRange(duplicate, 1, 0, scope);
|
||||
verifyEmpty(omResultNone);
|
||||
});
|
||||
|
||||
it('should extract the original array correctly', function() {
|
||||
var sourceArray = [
|
||||
{uniqueID: 'x', val: 'xx'},
|
||||
{uniqueID: 'y', val: 'yy'},
|
||||
{uniqueID: 'z', val: 'zz'},
|
||||
];
|
||||
var om = OrderedMap.fromArray(sourceArray, extractUniqueID);
|
||||
expect(om.toArray()).toEqual(sourceArray);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user