From 5379c1996b521f5e702f4aa036fa1c53e9d1e486 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 10 Jan 2015 12:55:03 -0800 Subject: [PATCH 01/67] Bump to v3.0.0. --- .gitattributes | 1 + .gitignore | 3 + .npmignore | 1 + LICENSE.txt | 22 ++ README.md | 8 + array.js | 81 +++++ array/chunk.js | 47 +++ array/compact.js | 30 ++ array/difference.js | 39 +++ array/drop.js | 40 +++ array/dropRight.js | 41 +++ array/dropRightWhile.js | 54 +++ array/dropWhile.js | 55 +++ array/findIndex.js | 55 +++ array/findLastIndex.js | 53 +++ array/first.js | 22 ++ array/flatten.js | 32 ++ array/flattenDeep.js | 21 ++ array/head.js | 2 + array/indexOf.js | 55 +++ array/initial.js | 20 ++ array/intersection.js | 68 ++++ array/last.js | 19 ++ array/lastIndexOf.js | 57 ++++ array/object.js | 2 + array/pull.js | 52 +++ array/pullAt.js | 33 ++ array/remove.js | 60 ++++ array/rest.js | 21 ++ array/slice.js | 30 ++ array/sortedIndex.js | 56 +++ array/sortedLastIndex.js | 32 ++ array/tail.js | 2 + array/take.js | 40 +++ array/takeRight.js | 41 +++ array/takeRightWhile.js | 54 +++ array/takeWhile.js | 55 +++ array/union.js | 27 ++ array/uniq.js | 71 ++++ array/unique.js | 2 + array/unzip.js | 37 ++ array/without.js | 28 ++ array/xor.js | 39 +++ array/zip.js | 28 ++ array/zipObject.js | 39 +++ chain.js | 23 ++ chain/chain.js | 33 ++ chain/lodash.js | 109 ++++++ chain/reverse.js | 2 + chain/tap.js | 27 ++ chain/thru.js | 23 ++ chain/toJSON.js | 2 + chain/toString.js | 2 + chain/value.js | 2 + chain/valueOf.js | 2 + chain/wrapperChain.js | 32 ++ chain/wrapperReverse.js | 35 ++ chain/wrapperToString.js | 17 + chain/wrapperValue.js | 20 ++ collection.js | 83 +++++ collection/all.js | 2 + collection/any.js | 2 + collection/at.js | 34 ++ collection/collect.js | 2 + collection/contains.js | 2 + collection/countBy.js | 47 +++ collection/detect.js | 2 + collection/each.js | 2 + collection/eachRight.js | 2 + collection/every.js | 55 +++ collection/filter.js | 52 +++ collection/find.js | 57 ++++ collection/findLast.js | 28 ++ collection/findWhere.js | 32 ++ collection/foldl.js | 2 + collection/foldr.js | 2 + collection/forEach.js | 38 +++ collection/forEachRight.js | 29 ++ collection/groupBy.js | 52 +++ collection/include.js | 2 + collection/includes.js | 61 ++++ collection/indexBy.js | 46 +++ collection/inject.js | 2 + collection/invoke.js | 30 ++ collection/map.js | 51 +++ collection/max.js | 49 +++ collection/min.js | 49 +++ collection/partition.js | 51 +++ collection/pluck.js | 31 ++ collection/reduce.js | 40 +++ collection/reduceRight.js | 31 ++ collection/reject.js | 52 +++ collection/sample.js | 38 +++ collection/select.js | 2 + collection/shuffle.js | 36 ++ collection/size.js | 29 ++ collection/some.js | 56 +++ collection/sortBy.js | 64 ++++ collection/sortByAll.js | 53 +++ collection/where.js | 35 ++ date.js | 5 + date/now.js | 22 ++ function.js | 49 +++ function/after.js | 51 +++ function/ary.js | 34 ++ function/backflow.js | 2 + function/before.js | 43 +++ function/bind.js | 58 ++++ function/bindAll.js | 39 +++ function/bindKey.js | 68 ++++ function/compose.js | 2 + function/curry.js | 59 ++++ function/curryRight.js | 56 +++ function/debounce.js | 187 ++++++++++ function/defer.js | 22 ++ function/delay.js | 23 ++ function/flow.js | 52 +++ function/flowRight.js | 52 +++ function/memoize.js | 82 +++++ function/negate.js | 34 ++ function/once.js | 25 ++ function/partial.js | 50 +++ function/partialRight.js | 49 +++ function/rearg.js | 38 +++ function/throttle.js | 72 ++++ function/wrap.js | 33 ++ internal/LazyWrapper.js | 21 ++ internal/LodashWrapper.js | 15 + internal/MapCache.js | 24 ++ internal/SetCache.js | 30 ++ internal/arrayCopy.js | 20 ++ internal/arrayEach.js | 22 ++ internal/arrayEachRight.js | 21 ++ internal/arrayEvery.js | 23 ++ internal/arrayFilter.js | 25 ++ internal/arrayMap.js | 21 ++ internal/arrayMax.js | 25 ++ internal/arrayMin.js | 25 ++ internal/arrayReduce.js | 26 ++ internal/arrayReduceRight.js | 24 ++ internal/arraySome.js | 23 ++ internal/assignDefaults.js | 13 + internal/assignOwnDefaults.js | 26 ++ internal/baseAssign.js | 35 ++ internal/baseAt.js | 32 ++ internal/baseBindAll.js | 26 ++ internal/baseCallback.js | 34 ++ internal/baseClone.js | 130 +++++++ internal/baseCompareAscending.js | 25 ++ internal/baseCopy.js | 25 ++ internal/baseCreate.js | 24 ++ internal/baseDelay.js | 24 ++ internal/baseDifference.js | 52 +++ internal/baseEach.js | 30 ++ internal/baseEachRight.js | 28 ++ internal/baseEvery.js | 22 ++ internal/baseFilter.js | 22 ++ internal/baseFind.js | 25 ++ internal/baseFlatten.js | 45 +++ internal/baseFor.js | 30 ++ internal/baseForIn.js | 17 + internal/baseForOwn.js | 17 + internal/baseForOwnRight.js | 17 + internal/baseForRight.js | 27 ++ internal/baseFunctions.js | 27 ++ internal/baseIndexOf.js | 27 ++ internal/baseInvoke.js | 28 ++ internal/baseIsEqual.js | 34 ++ internal/baseIsEqualDeep.js | 101 ++++++ internal/baseIsMatch.js | 58 ++++ internal/baseMap.js | 20 ++ internal/baseMatches.js | 51 +++ internal/baseMerge.js | 45 +++ internal/baseMergeDeep.js | 64 ++++ internal/baseProperty.js | 14 + internal/basePullAt.js | 35 ++ internal/baseRandom.js | 20 ++ internal/baseReduce.js | 24 ++ internal/baseSetData.js | 17 + internal/baseSlice.js | 31 ++ internal/baseSome.js | 23 ++ internal/baseSortBy.js | 21 ++ internal/baseToString.js | 16 + internal/baseUniq.js | 57 ++++ internal/baseValues.js | 22 ++ internal/baseWrapperValue.js | 37 ++ internal/binaryIndex.js | 40 +++ internal/binaryIndexBy.js | 54 +++ internal/bindCallback.js | 39 +++ internal/bufferClone.js | 56 +++ internal/cacheIndexOf.js | 19 ++ internal/cachePush.js | 20 ++ internal/charAtCallback.js | 12 + internal/charsLeftIndex.js | 18 + internal/charsRightIndex.js | 17 + internal/compareAscending.js | 16 + internal/compareMultipleAscending.js | 34 ++ internal/composeArgs.js | 34 ++ internal/composeArgsRight.js | 36 ++ internal/createAggregator.js | 38 +++ internal/createAssigner.js | 40 +++ internal/createBindWrapper.js | 21 ++ internal/createCache.js | 23 ++ internal/createCompounder.js | 26 ++ internal/createCtorWrapper.js | 23 ++ internal/createExtremum.js | 38 +++ internal/createHybridWrapper.js | 104 ++++++ internal/createPad.js | 34 ++ internal/createPartialWrapper.js | 42 +++ internal/createWrapper.js | 87 +++++ internal/deburrLetter.js | 33 ++ internal/equalArrays.js | 54 +++ internal/equalByTag.js | 51 +++ internal/equalObjects.js | 72 ++++ internal/escapeHtmlChar.js | 22 ++ internal/escapeStringChar.js | 23 ++ internal/extremumBy.js | 34 ++ internal/getData.js | 15 + internal/getView.js | 33 ++ internal/indexOfNaN.js | 24 ++ internal/initCloneArray.js | 26 ++ internal/initCloneByTag.js | 64 ++++ internal/initCloneObject.js | 16 + internal/isBindable.js | 38 +++ internal/isIndex.js | 22 ++ internal/isIterateeCall.js | 28 ++ internal/isLength.js | 19 ++ internal/isObjectLike.js | 12 + internal/isSpace.js | 14 + internal/isStrictComparable.js | 15 + internal/lazyClone.js | 28 ++ internal/lazyReverse.js | 20 ++ internal/lazyValue.js | 71 ++++ internal/mapDelete.js | 14 + internal/mapGet.js | 14 + internal/mapHas.js | 20 ++ internal/mapSet.js | 18 + internal/mergeData.js | 99 ++++++ internal/metaMap.js | 10 + internal/pickByArray.js | 28 ++ internal/pickByCallback.js | 22 ++ internal/reEscape.js | 4 + internal/reEvaluate.js | 4 + internal/reInterpolate.js | 4 + internal/reorder.js | 29 ++ internal/replaceHolders.js | 28 ++ internal/root.js | 27 ++ internal/setData.js | 41 +++ internal/shimIsPlainObject.js | 51 +++ internal/shimKeys.js | 42 +++ internal/sortedUniq.js | 29 ++ internal/toIterable.js | 22 ++ internal/toObject.js | 14 + internal/trimmedLeftIndex.js | 19 ++ internal/trimmedRightIndex.js | 18 + internal/unescapeHtmlChar.js | 22 ++ lang.js | 53 +++ lang/clone.js | 65 ++++ lang/cloneDeep.js | 52 +++ lang/isArguments.js | 38 +++ lang/isArray.js | 41 +++ lang/isBoolean.js | 36 ++ lang/isDate.js | 36 ++ lang/isElement.js | 42 +++ lang/isEmpty.js | 48 +++ lang/isEqual.js | 54 +++ lang/isError.js | 37 ++ lang/isFinite.js | 41 +++ lang/isFunction.js | 51 +++ lang/isMatch.js | 74 ++++ lang/isNaN.js | 35 ++ lang/isNative.js | 55 +++ lang/isNull.js | 21 ++ lang/isNumber.js | 42 +++ lang/isObject.js | 30 ++ lang/isPlainObject.js | 62 ++++ lang/isRegExp.js | 36 ++ lang/isString.js | 36 ++ lang/isTypedArray.js | 75 +++++ lang/isUndefined.js | 21 ++ lang/toArray.js | 29 ++ lang/toPlainObject.js | 31 ++ lodash.js | 487 +++++++++++++++++++++++++++ number.js | 5 + number/random.js | 70 ++++ object.js | 53 +++ object/assign.js | 35 ++ object/create.js | 46 +++ object/defaults.js | 30 ++ object/extend.js | 2 + object/findKey.js | 49 +++ object/findLastKey.js | 49 +++ object/forIn.js | 39 +++ object/forInRight.js | 35 ++ object/forOwn.js | 31 ++ object/forOwnRight.js | 28 ++ object/functions.js | 23 ++ object/has.js | 26 ++ object/invert.js | 62 ++++ object/keys.js | 48 +++ object/keysIn.js | 65 ++++ object/mapValues.js | 50 +++ object/merge.js | 52 +++ object/methods.js | 2 + object/omit.js | 51 +++ object/pairs.js | 30 ++ object/pick.js | 41 +++ object/result.js | 41 +++ object/transform.js | 62 ++++ object/values.js | 33 ++ object/valuesIn.js | 31 ++ package.json | 20 ++ string.js | 47 +++ string/camelCase.js | 28 ++ string/capitalize.js | 21 ++ string/deburr.js | 27 ++ string/endsWith.js | 36 ++ string/escape.js | 48 +++ string/escapeRegExp.js | 32 ++ string/kebabCase.js | 28 ++ string/pad.js | 51 +++ string/padLeft.js | 32 ++ string/padRight.js | 32 ++ string/parseInt.js | 68 ++++ string/repeat.js | 50 +++ string/snakeCase.js | 27 ++ string/startsWith.js | 33 ++ string/template.js | 229 +++++++++++++ string/templateSettings.js | 67 ++++ string/trim.js | 42 +++ string/trimLeft.js | 36 ++ string/trimRight.js | 36 ++ string/trunc.js | 97 ++++++ string/unescape.js | 33 ++ string/words.js | 38 +++ support.js | 76 +++++ utility.js | 29 ++ utility/attempt.js | 31 ++ utility/callback.js | 46 +++ utility/constant.js | 22 ++ utility/identity.js | 19 ++ utility/iteratee.js | 2 + utility/matches.js | 32 ++ utility/mixin.js | 84 +++++ utility/noop.js | 17 + utility/property.js | 30 ++ utility/propertyOf.js | 26 ++ utility/range.js | 67 ++++ utility/times.js | 56 +++ utility/uniqueId.js | 27 ++ 350 files changed, 12910 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 array.js create mode 100644 array/chunk.js create mode 100644 array/compact.js create mode 100644 array/difference.js create mode 100644 array/drop.js create mode 100644 array/dropRight.js create mode 100644 array/dropRightWhile.js create mode 100644 array/dropWhile.js create mode 100644 array/findIndex.js create mode 100644 array/findLastIndex.js create mode 100644 array/first.js create mode 100644 array/flatten.js create mode 100644 array/flattenDeep.js create mode 100644 array/head.js create mode 100644 array/indexOf.js create mode 100644 array/initial.js create mode 100644 array/intersection.js create mode 100644 array/last.js create mode 100644 array/lastIndexOf.js create mode 100644 array/object.js create mode 100644 array/pull.js create mode 100644 array/pullAt.js create mode 100644 array/remove.js create mode 100644 array/rest.js create mode 100644 array/slice.js create mode 100644 array/sortedIndex.js create mode 100644 array/sortedLastIndex.js create mode 100644 array/tail.js create mode 100644 array/take.js create mode 100644 array/takeRight.js create mode 100644 array/takeRightWhile.js create mode 100644 array/takeWhile.js create mode 100644 array/union.js create mode 100644 array/uniq.js create mode 100644 array/unique.js create mode 100644 array/unzip.js create mode 100644 array/without.js create mode 100644 array/xor.js create mode 100644 array/zip.js create mode 100644 array/zipObject.js create mode 100644 chain.js create mode 100644 chain/chain.js create mode 100644 chain/lodash.js create mode 100644 chain/reverse.js create mode 100644 chain/tap.js create mode 100644 chain/thru.js create mode 100644 chain/toJSON.js create mode 100644 chain/toString.js create mode 100644 chain/value.js create mode 100644 chain/valueOf.js create mode 100644 chain/wrapperChain.js create mode 100644 chain/wrapperReverse.js create mode 100644 chain/wrapperToString.js create mode 100644 chain/wrapperValue.js create mode 100644 collection.js create mode 100644 collection/all.js create mode 100644 collection/any.js create mode 100644 collection/at.js create mode 100644 collection/collect.js create mode 100644 collection/contains.js create mode 100644 collection/countBy.js create mode 100644 collection/detect.js create mode 100644 collection/each.js create mode 100644 collection/eachRight.js create mode 100644 collection/every.js create mode 100644 collection/filter.js create mode 100644 collection/find.js create mode 100644 collection/findLast.js create mode 100644 collection/findWhere.js create mode 100644 collection/foldl.js create mode 100644 collection/foldr.js create mode 100644 collection/forEach.js create mode 100644 collection/forEachRight.js create mode 100644 collection/groupBy.js create mode 100644 collection/include.js create mode 100644 collection/includes.js create mode 100644 collection/indexBy.js create mode 100644 collection/inject.js create mode 100644 collection/invoke.js create mode 100644 collection/map.js create mode 100644 collection/max.js create mode 100644 collection/min.js create mode 100644 collection/partition.js create mode 100644 collection/pluck.js create mode 100644 collection/reduce.js create mode 100644 collection/reduceRight.js create mode 100644 collection/reject.js create mode 100644 collection/sample.js create mode 100644 collection/select.js create mode 100644 collection/shuffle.js create mode 100644 collection/size.js create mode 100644 collection/some.js create mode 100644 collection/sortBy.js create mode 100644 collection/sortByAll.js create mode 100644 collection/where.js create mode 100644 date.js create mode 100644 date/now.js create mode 100644 function.js create mode 100644 function/after.js create mode 100644 function/ary.js create mode 100644 function/backflow.js create mode 100644 function/before.js create mode 100644 function/bind.js create mode 100644 function/bindAll.js create mode 100644 function/bindKey.js create mode 100644 function/compose.js create mode 100644 function/curry.js create mode 100644 function/curryRight.js create mode 100644 function/debounce.js create mode 100644 function/defer.js create mode 100644 function/delay.js create mode 100644 function/flow.js create mode 100644 function/flowRight.js create mode 100644 function/memoize.js create mode 100644 function/negate.js create mode 100644 function/once.js create mode 100644 function/partial.js create mode 100644 function/partialRight.js create mode 100644 function/rearg.js create mode 100644 function/throttle.js create mode 100644 function/wrap.js create mode 100644 internal/LazyWrapper.js create mode 100644 internal/LodashWrapper.js create mode 100644 internal/MapCache.js create mode 100644 internal/SetCache.js create mode 100644 internal/arrayCopy.js create mode 100644 internal/arrayEach.js create mode 100644 internal/arrayEachRight.js create mode 100644 internal/arrayEvery.js create mode 100644 internal/arrayFilter.js create mode 100644 internal/arrayMap.js create mode 100644 internal/arrayMax.js create mode 100644 internal/arrayMin.js create mode 100644 internal/arrayReduce.js create mode 100644 internal/arrayReduceRight.js create mode 100644 internal/arraySome.js create mode 100644 internal/assignDefaults.js create mode 100644 internal/assignOwnDefaults.js create mode 100644 internal/baseAssign.js create mode 100644 internal/baseAt.js create mode 100644 internal/baseBindAll.js create mode 100644 internal/baseCallback.js create mode 100644 internal/baseClone.js create mode 100644 internal/baseCompareAscending.js create mode 100644 internal/baseCopy.js create mode 100644 internal/baseCreate.js create mode 100644 internal/baseDelay.js create mode 100644 internal/baseDifference.js create mode 100644 internal/baseEach.js create mode 100644 internal/baseEachRight.js create mode 100644 internal/baseEvery.js create mode 100644 internal/baseFilter.js create mode 100644 internal/baseFind.js create mode 100644 internal/baseFlatten.js create mode 100644 internal/baseFor.js create mode 100644 internal/baseForIn.js create mode 100644 internal/baseForOwn.js create mode 100644 internal/baseForOwnRight.js create mode 100644 internal/baseForRight.js create mode 100644 internal/baseFunctions.js create mode 100644 internal/baseIndexOf.js create mode 100644 internal/baseInvoke.js create mode 100644 internal/baseIsEqual.js create mode 100644 internal/baseIsEqualDeep.js create mode 100644 internal/baseIsMatch.js create mode 100644 internal/baseMap.js create mode 100644 internal/baseMatches.js create mode 100644 internal/baseMerge.js create mode 100644 internal/baseMergeDeep.js create mode 100644 internal/baseProperty.js create mode 100644 internal/basePullAt.js create mode 100644 internal/baseRandom.js create mode 100644 internal/baseReduce.js create mode 100644 internal/baseSetData.js create mode 100644 internal/baseSlice.js create mode 100644 internal/baseSome.js create mode 100644 internal/baseSortBy.js create mode 100644 internal/baseToString.js create mode 100644 internal/baseUniq.js create mode 100644 internal/baseValues.js create mode 100644 internal/baseWrapperValue.js create mode 100644 internal/binaryIndex.js create mode 100644 internal/binaryIndexBy.js create mode 100644 internal/bindCallback.js create mode 100644 internal/bufferClone.js create mode 100644 internal/cacheIndexOf.js create mode 100644 internal/cachePush.js create mode 100644 internal/charAtCallback.js create mode 100644 internal/charsLeftIndex.js create mode 100644 internal/charsRightIndex.js create mode 100644 internal/compareAscending.js create mode 100644 internal/compareMultipleAscending.js create mode 100644 internal/composeArgs.js create mode 100644 internal/composeArgsRight.js create mode 100644 internal/createAggregator.js create mode 100644 internal/createAssigner.js create mode 100644 internal/createBindWrapper.js create mode 100644 internal/createCache.js create mode 100644 internal/createCompounder.js create mode 100644 internal/createCtorWrapper.js create mode 100644 internal/createExtremum.js create mode 100644 internal/createHybridWrapper.js create mode 100644 internal/createPad.js create mode 100644 internal/createPartialWrapper.js create mode 100644 internal/createWrapper.js create mode 100644 internal/deburrLetter.js create mode 100644 internal/equalArrays.js create mode 100644 internal/equalByTag.js create mode 100644 internal/equalObjects.js create mode 100644 internal/escapeHtmlChar.js create mode 100644 internal/escapeStringChar.js create mode 100644 internal/extremumBy.js create mode 100644 internal/getData.js create mode 100644 internal/getView.js create mode 100644 internal/indexOfNaN.js create mode 100644 internal/initCloneArray.js create mode 100644 internal/initCloneByTag.js create mode 100644 internal/initCloneObject.js create mode 100644 internal/isBindable.js create mode 100644 internal/isIndex.js create mode 100644 internal/isIterateeCall.js create mode 100644 internal/isLength.js create mode 100644 internal/isObjectLike.js create mode 100644 internal/isSpace.js create mode 100644 internal/isStrictComparable.js create mode 100644 internal/lazyClone.js create mode 100644 internal/lazyReverse.js create mode 100644 internal/lazyValue.js create mode 100644 internal/mapDelete.js create mode 100644 internal/mapGet.js create mode 100644 internal/mapHas.js create mode 100644 internal/mapSet.js create mode 100644 internal/mergeData.js create mode 100644 internal/metaMap.js create mode 100644 internal/pickByArray.js create mode 100644 internal/pickByCallback.js create mode 100644 internal/reEscape.js create mode 100644 internal/reEvaluate.js create mode 100644 internal/reInterpolate.js create mode 100644 internal/reorder.js create mode 100644 internal/replaceHolders.js create mode 100644 internal/root.js create mode 100644 internal/setData.js create mode 100644 internal/shimIsPlainObject.js create mode 100644 internal/shimKeys.js create mode 100644 internal/sortedUniq.js create mode 100644 internal/toIterable.js create mode 100644 internal/toObject.js create mode 100644 internal/trimmedLeftIndex.js create mode 100644 internal/trimmedRightIndex.js create mode 100644 internal/unescapeHtmlChar.js create mode 100644 lang.js create mode 100644 lang/clone.js create mode 100644 lang/cloneDeep.js create mode 100644 lang/isArguments.js create mode 100644 lang/isArray.js create mode 100644 lang/isBoolean.js create mode 100644 lang/isDate.js create mode 100644 lang/isElement.js create mode 100644 lang/isEmpty.js create mode 100644 lang/isEqual.js create mode 100644 lang/isError.js create mode 100644 lang/isFinite.js create mode 100644 lang/isFunction.js create mode 100644 lang/isMatch.js create mode 100644 lang/isNaN.js create mode 100644 lang/isNative.js create mode 100644 lang/isNull.js create mode 100644 lang/isNumber.js create mode 100644 lang/isObject.js create mode 100644 lang/isPlainObject.js create mode 100644 lang/isRegExp.js create mode 100644 lang/isString.js create mode 100644 lang/isTypedArray.js create mode 100644 lang/isUndefined.js create mode 100644 lang/toArray.js create mode 100644 lang/toPlainObject.js create mode 100644 lodash.js create mode 100644 number.js create mode 100644 number/random.js create mode 100644 object.js create mode 100644 object/assign.js create mode 100644 object/create.js create mode 100644 object/defaults.js create mode 100644 object/extend.js create mode 100644 object/findKey.js create mode 100644 object/findLastKey.js create mode 100644 object/forIn.js create mode 100644 object/forInRight.js create mode 100644 object/forOwn.js create mode 100644 object/forOwnRight.js create mode 100644 object/functions.js create mode 100644 object/has.js create mode 100644 object/invert.js create mode 100644 object/keys.js create mode 100644 object/keysIn.js create mode 100644 object/mapValues.js create mode 100644 object/merge.js create mode 100644 object/methods.js create mode 100644 object/omit.js create mode 100644 object/pairs.js create mode 100644 object/pick.js create mode 100644 object/result.js create mode 100644 object/transform.js create mode 100644 object/values.js create mode 100644 object/valuesIn.js create mode 100644 package.json create mode 100644 string.js create mode 100644 string/camelCase.js create mode 100644 string/capitalize.js create mode 100644 string/deburr.js create mode 100644 string/endsWith.js create mode 100644 string/escape.js create mode 100644 string/escapeRegExp.js create mode 100644 string/kebabCase.js create mode 100644 string/pad.js create mode 100644 string/padLeft.js create mode 100644 string/padRight.js create mode 100644 string/parseInt.js create mode 100644 string/repeat.js create mode 100644 string/snakeCase.js create mode 100644 string/startsWith.js create mode 100644 string/template.js create mode 100644 string/templateSettings.js create mode 100644 string/trim.js create mode 100644 string/trimLeft.js create mode 100644 string/trimRight.js create mode 100644 string/trunc.js create mode 100644 string/unescape.js create mode 100644 string/words.js create mode 100644 support.js create mode 100644 utility.js create mode 100644 utility/attempt.js create mode 100644 utility/callback.js create mode 100644 utility/constant.js create mode 100644 utility/identity.js create mode 100644 utility/iteratee.js create mode 100644 utility/matches.js create mode 100644 utility/mixin.js create mode 100644 utility/noop.js create mode 100644 utility/property.js create mode 100644 utility/propertyOf.js create mode 100644 utility/range.js create mode 100644 utility/times.js create mode 100644 utility/uniqueId.js diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..176a458f94 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..d7e3a4e8e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +*.log +node_modules diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000000..8d98f9debd --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +.* diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000000..17764328c8 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2015 The Dojo Foundation +Based on Underscore.js 1.7.0, copyright 2009-2015 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..1d746ef3e9 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# lodash-es v3.0.0 + +The [modern build](https://github.com/lodash/lodash/wiki/Build-Differences) of [lodash](https://lodash.com/) exported as [ES](https://people.mozilla.org/~jorendorff/es6-draft.html) modules. + +Generated using [lodash-cli](https://www.npmjs.com/package/lodash-cli): +```bash +$ lodash modularize modern exports=es -o ./ +``` diff --git a/array.js b/array.js new file mode 100644 index 0000000000..0f83e0c74e --- /dev/null +++ b/array.js @@ -0,0 +1,81 @@ +import chunk from './array/chunk'; +import compact from './array/compact'; +import difference from './array/difference'; +import drop from './array/drop'; +import dropRight from './array/dropRight'; +import dropRightWhile from './array/dropRightWhile'; +import dropWhile from './array/dropWhile'; +import findIndex from './array/findIndex'; +import findLastIndex from './array/findLastIndex'; +import first from './array/first'; +import flatten from './array/flatten'; +import flattenDeep from './array/flattenDeep'; +import head from './array/head'; +import indexOf from './array/indexOf'; +import initial from './array/initial'; +import intersection from './array/intersection'; +import last from './array/last'; +import lastIndexOf from './array/lastIndexOf'; +import object from './array/object'; +import pull from './array/pull'; +import pullAt from './array/pullAt'; +import remove from './array/remove'; +import rest from './array/rest'; +import slice from './array/slice'; +import sortedIndex from './array/sortedIndex'; +import sortedLastIndex from './array/sortedLastIndex'; +import tail from './array/tail'; +import take from './array/take'; +import takeRight from './array/takeRight'; +import takeRightWhile from './array/takeRightWhile'; +import takeWhile from './array/takeWhile'; +import union from './array/union'; +import uniq from './array/uniq'; +import unique from './array/unique'; +import unzip from './array/unzip'; +import without from './array/without'; +import xor from './array/xor'; +import zip from './array/zip'; +import zipObject from './array/zipObject'; + +export default { + 'chunk': chunk, + 'compact': compact, + 'difference': difference, + 'drop': drop, + 'dropRight': dropRight, + 'dropRightWhile': dropRightWhile, + 'dropWhile': dropWhile, + 'findIndex': findIndex, + 'findLastIndex': findLastIndex, + 'first': first, + 'flatten': flatten, + 'flattenDeep': flattenDeep, + 'head': head, + 'indexOf': indexOf, + 'initial': initial, + 'intersection': intersection, + 'last': last, + 'lastIndexOf': lastIndexOf, + 'object': object, + 'pull': pull, + 'pullAt': pullAt, + 'remove': remove, + 'rest': rest, + 'slice': slice, + 'sortedIndex': sortedIndex, + 'sortedLastIndex': sortedLastIndex, + 'tail': tail, + 'take': take, + 'takeRight': takeRight, + 'takeRightWhile': takeRightWhile, + 'takeWhile': takeWhile, + 'union': union, + 'uniq': uniq, + 'unique': unique, + 'unzip': unzip, + 'without': without, + 'xor': xor, + 'zip': zip, + 'zipObject': zipObject +}; diff --git a/array/chunk.js b/array/chunk.js new file mode 100644 index 0000000000..b402309b01 --- /dev/null +++ b/array/chunk.js @@ -0,0 +1,47 @@ +import baseSlice from '../internal/baseSlice'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** Native method references. */ +var ceil = Math.ceil; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * Creates an array of elements split into groups the length of `size`. + * If `collection` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to process. + * @param {numer} [size=1] The length of each chunk. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the new array containing chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ +function chunk(array, size, guard) { + if (guard ? isIterateeCall(array, size, guard) : size == null) { + size = 1; + } else { + size = nativeMax(+size || 1, 1); + } + var index = 0, + length = array ? array.length : 0, + resIndex = -1, + result = Array(ceil(length / size)); + + while (index < length) { + result[++resIndex] = baseSlice(array, index, (index += size)); + } + return result; +} + +export default chunk; diff --git a/array/compact.js b/array/compact.js new file mode 100644 index 0000000000..438719a211 --- /dev/null +++ b/array/compact.js @@ -0,0 +1,30 @@ +/** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ +function compact(array) { + var index = -1, + length = array ? array.length : 0, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[++resIndex] = value; + } + } + return result; +} + +export default compact; diff --git a/array/difference.js b/array/difference.js new file mode 100644 index 0000000000..a2945354eb --- /dev/null +++ b/array/difference.js @@ -0,0 +1,39 @@ +import baseDifference from '../internal/baseDifference'; +import baseFlatten from '../internal/baseFlatten'; +import isArguments from '../lang/isArguments'; +import isArray from '../lang/isArray'; + +/** + * Creates an array excluding all values of the provided arrays using + * `SameValueZero` for equality comparisons. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The arrays of values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.difference([1, 2, 3], [5, 2, 10]); + * // => [1, 3] + */ +function difference() { + var index = -1, + length = arguments.length; + + while (++index < length) { + var value = arguments[index]; + if (isArray(value) || isArguments(value)) { + break; + } + } + return baseDifference(value, baseFlatten(arguments, false, true, ++index)); +} + +export default difference; diff --git a/array/drop.js b/array/drop.js new file mode 100644 index 0000000000..a90f8bb3f5 --- /dev/null +++ b/array/drop.js @@ -0,0 +1,40 @@ +import baseSlice from '../internal/baseSlice'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ +function drop(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + return baseSlice(array, n < 0 ? 0 : n); +} + +export default drop; diff --git a/array/dropRight.js b/array/dropRight.js new file mode 100644 index 0000000000..c22bec9233 --- /dev/null +++ b/array/dropRight.js @@ -0,0 +1,41 @@ +import baseSlice from '../internal/baseSlice'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** + * Creates a slice of `array` with `n` elements dropped from the end. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRight([1, 2, 3]); + * // => [1, 2] + * + * _.dropRight([1, 2, 3], 2); + * // => [1] + * + * _.dropRight([1, 2, 3], 5); + * // => [] + * + * _.dropRight([1, 2, 3], 0); + * // => [1, 2, 3] + */ +function dropRight(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + n = length - (+n || 0); + return baseSlice(array, 0, n < 0 ? 0 : n); +} + +export default dropRight; diff --git a/array/dropRightWhile.js b/array/dropRightWhile.js new file mode 100644 index 0000000000..3e9c8883cf --- /dev/null +++ b/array/dropRightWhile.js @@ -0,0 +1,54 @@ +import baseCallback from '../internal/baseCallback'; +import baseSlice from '../internal/baseSlice'; + +/** + * Creates a slice of `array` excluding elements dropped from the end. + * Elements are dropped until `predicate` returns falsey. The predicate is + * bound to `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per element. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRightWhile([1, 2, 3], function(n) { return n > 1; }); + * // => [1] + * + * var users = [ + * { 'user': 'barney', 'status': 'busy', 'active': false }, + * { 'user': 'fred', 'status': 'busy', 'active': true }, + * { 'user': 'pebbles', 'status': 'away', 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.dropRightWhile(users, 'active'), 'user'); + * // => ['barney'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.dropRightWhile(users, { 'status': 'away' }), 'user'); + * // => ['barney', 'fred'] + */ +function dropRightWhile(array, predicate, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + predicate = baseCallback(predicate, thisArg, 3); + while (length-- && predicate(array[length], length, array)) {} + return baseSlice(array, 0, length + 1); +} + +export default dropRightWhile; diff --git a/array/dropWhile.js b/array/dropWhile.js new file mode 100644 index 0000000000..62a888f832 --- /dev/null +++ b/array/dropWhile.js @@ -0,0 +1,55 @@ +import baseCallback from '../internal/baseCallback'; +import baseSlice from '../internal/baseSlice'; + +/** + * Creates a slice of `array` excluding elements dropped from the beginning. + * Elements are dropped until `predicate` returns falsey. The predicate is + * bound to `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per element. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropWhile([1, 2, 3], function(n) { return n < 3; }); + * // => [3] + * + * var users = [ + * { 'user': 'barney', 'status': 'busy', 'active': true }, + * { 'user': 'fred', 'status': 'busy', 'active': false }, + * { 'user': 'pebbles', 'status': 'away', 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.dropWhile(users, 'active'), 'user'); + * // => ['fred', 'pebbles'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.dropWhile(users, { 'status': 'busy' }), 'user'); + * // => ['pebbles'] + */ +function dropWhile(array, predicate, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + var index = -1; + predicate = baseCallback(predicate, thisArg, 3); + while (++index < length && predicate(array[index], index, array)) {} + return baseSlice(array, index); +} + +export default dropWhile; diff --git a/array/findIndex.js b/array/findIndex.js new file mode 100644 index 0000000000..1c94a3efdd --- /dev/null +++ b/array/findIndex.js @@ -0,0 +1,55 @@ +import baseCallback from '../internal/baseCallback'; + +/** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for, instead of the element itself. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.findIndex(users, function(chr) { return chr.age < 40; }); + * // => 0 + * + * // using the "_.matches" callback shorthand + * _.findIndex(users, { 'age': 1 }); + * // => 2 + * + * // using the "_.property" callback shorthand + * _.findIndex(users, 'active'); + * // => 1 + */ +function findIndex(array, predicate, thisArg) { + var index = -1, + length = array ? array.length : 0; + + predicate = baseCallback(predicate, thisArg, 3); + while (++index < length) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; +} + +export default findIndex; diff --git a/array/findLastIndex.js b/array/findLastIndex.js new file mode 100644 index 0000000000..4adbf204f7 --- /dev/null +++ b/array/findLastIndex.js @@ -0,0 +1,53 @@ +import baseCallback from '../internal/baseCallback'; + +/** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.findLastIndex(users, function(chr) { return chr.age < 40; }); + * // => 2 + * + * // using the "_.matches" callback shorthand + * _.findLastIndex(users, { 'age': 40 }); + * // => 1 + * + * // using the "_.property" callback shorthand + * _.findLastIndex(users, 'active'); + * // => 0 + */ +function findLastIndex(array, predicate, thisArg) { + var length = array ? array.length : 0; + predicate = baseCallback(predicate, thisArg, 3); + while (length--) { + if (predicate(array[length], length, array)) { + return length; + } + } + return -1; +} + +export default findLastIndex; diff --git a/array/first.js b/array/first.js new file mode 100644 index 0000000000..e5f259842f --- /dev/null +++ b/array/first.js @@ -0,0 +1,22 @@ +/** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @alias head + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.first([1, 2, 3]); + * // => 1 + * + * _.first([]); + * // => undefined + */ +function first(array) { + return array ? array[0] : undefined; +} + +export default first; diff --git a/array/flatten.js b/array/flatten.js new file mode 100644 index 0000000000..4cad911698 --- /dev/null +++ b/array/flatten.js @@ -0,0 +1,32 @@ +import baseFlatten from '../internal/baseFlatten'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** + * Flattens a nested array. If `isDeep` is `true` the array is recursively + * flattened, otherwise it is only flattened a single level. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to flatten. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2], [3, [[4]]]]); + * // => [1, 2, 3, [[4]]]; + * + * // using `isDeep` + * _.flatten([1, [2], [3, [[4]]]], true); + * // => [1, 2, 3, 4]; + */ +function flatten(array, isDeep, guard) { + var length = array ? array.length : 0; + if (guard && isIterateeCall(array, isDeep, guard)) { + isDeep = false; + } + return length ? baseFlatten(array, isDeep) : []; +} + +export default flatten; diff --git a/array/flattenDeep.js b/array/flattenDeep.js new file mode 100644 index 0000000000..af20fa54aa --- /dev/null +++ b/array/flattenDeep.js @@ -0,0 +1,21 @@ +import baseFlatten from '../internal/baseFlatten'; + +/** + * Recursively flattens a nested array. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to recursively flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2], [3, [[4]]]]); + * // => [1, 2, 3, 4]; + */ +function flattenDeep(array) { + var length = array ? array.length : 0; + return length ? baseFlatten(array, true) : []; +} + +export default flattenDeep; diff --git a/array/head.js b/array/head.js new file mode 100644 index 0000000000..d29f169044 --- /dev/null +++ b/array/head.js @@ -0,0 +1,2 @@ +import first from './first' +export default first; diff --git a/array/indexOf.js b/array/indexOf.js new file mode 100644 index 0000000000..6bc7d09629 --- /dev/null +++ b/array/indexOf.js @@ -0,0 +1,55 @@ +import baseIndexOf from '../internal/baseIndexOf'; +import binaryIndex from '../internal/binaryIndex'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * Gets the index at which the first occurrence of `value` is found in `array` + * using `SameValueZero` for equality comparisons. If `fromIndex` is negative, + * it is used as the offset from the end of `array`. If `array` is sorted + * providing `true` for `fromIndex` performs a faster binary search. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {boolean|number} [fromIndex=0] The index to search from or `true` + * to perform a binary search on a sorted array. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 3, 1, 2, 3], 2); + * // => 1 + * + * // using `fromIndex` + * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); + * // => 4 + * + * // performing a binary search + * _.indexOf([4, 4, 5, 5, 6, 6], 5, true); + * // => 2 + */ +function indexOf(array, value, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + if (typeof fromIndex == 'number') { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); + } else if (fromIndex) { + var index = binaryIndex(array, value), + other = array[index]; + + return (value === value ? value === other : other !== other) ? index : -1; + } + return baseIndexOf(array, value, fromIndex); +} + +export default indexOf; diff --git a/array/initial.js b/array/initial.js new file mode 100644 index 0000000000..d0297c33bf --- /dev/null +++ b/array/initial.js @@ -0,0 +1,20 @@ +import dropRight from './dropRight'; + +/** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ +function initial(array) { + return dropRight(array, 1); +} + +export default initial; diff --git a/array/intersection.js b/array/intersection.js new file mode 100644 index 0000000000..70f169fbef --- /dev/null +++ b/array/intersection.js @@ -0,0 +1,68 @@ +import baseIndexOf from '../internal/baseIndexOf'; +import cacheIndexOf from '../internal/cacheIndexOf'; +import createCache from '../internal/createCache'; +import isArguments from '../lang/isArguments'; +import isArray from '../lang/isArray'; + +/** + * Creates an array of unique values in all provided arrays using `SameValueZero` + * for equality comparisons. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of shared values. + * @example + * + * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]); + * // => [1, 2] + */ +function intersection() { + var args = [], + argsIndex = -1, + argsLength = arguments.length, + caches = [], + indexOf = baseIndexOf, + isCommon = true; + + while (++argsIndex < argsLength) { + var value = arguments[argsIndex]; + if (isArray(value) || isArguments(value)) { + args.push(value); + caches.push(isCommon && value.length >= 120 && createCache(argsIndex && value)); + } + } + argsLength = args.length; + var array = args[0], + index = -1, + length = array ? array.length : 0, + result = [], + seen = caches[0]; + + outer: + while (++index < length) { + value = array[index]; + if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value)) < 0) { + argsIndex = argsLength; + while (--argsIndex) { + var cache = caches[argsIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { + continue outer; + } + } + if (seen) { + seen.push(value); + } + result.push(value); + } + } + return result; +} + +export default intersection; diff --git a/array/last.js b/array/last.js new file mode 100644 index 0000000000..6b83f62e97 --- /dev/null +++ b/array/last.js @@ -0,0 +1,19 @@ +/** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ +function last(array) { + var length = array ? array.length : 0; + return length ? array[length - 1] : undefined; +} + +export default last; diff --git a/array/lastIndexOf.js b/array/lastIndexOf.js new file mode 100644 index 0000000000..14e6dab48b --- /dev/null +++ b/array/lastIndexOf.js @@ -0,0 +1,57 @@ +import binaryIndex from '../internal/binaryIndex'; +import indexOfNaN from '../internal/indexOfNaN'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max, + nativeMin = Math.min; + +/** + * This method is like `_.indexOf` except that it iterates over elements of + * `array` from right to left. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {boolean|number} [fromIndex=array.length-1] The index to search from + * or `true` to perform a binary search on a sorted array. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); + * // => 4 + * + * // using `fromIndex` + * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); + * // => 1 + * + * // performing a binary search + * _.lastIndexOf([4, 4, 5, 5, 6, 6], 5, true); + * // => 3 + */ +function lastIndexOf(array, value, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + var index = length; + if (typeof fromIndex == 'number') { + index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1; + } else if (fromIndex) { + index = binaryIndex(array, value, true) - 1; + var other = array[index]; + return (value === value ? value === other : other !== other) ? index : -1; + } + if (value !== value) { + return indexOfNaN(array, index, true); + } + while (index--) { + if (array[index] === value) { + return index; + } + } + return -1; +} + +export default lastIndexOf; diff --git a/array/object.js b/array/object.js new file mode 100644 index 0000000000..ac9db159cf --- /dev/null +++ b/array/object.js @@ -0,0 +1,2 @@ +import zipObject from './zipObject' +export default zipObject; diff --git a/array/pull.js b/array/pull.js new file mode 100644 index 0000000000..b69ed3e21f --- /dev/null +++ b/array/pull.js @@ -0,0 +1,52 @@ +import baseIndexOf from '../internal/baseIndexOf'; + +/** Used for native method references. */ +var arrayProto = Array.prototype; + +/** Native method references. */ +var splice = arrayProto.splice; + +/** + * Removes all provided values from `array` using `SameValueZero` for equality + * comparisons. + * + * **Notes:** + * - Unlike `_.without`, this method mutates `array`. + * - `SameValueZero` comparisons are like strict equality comparisons, e.g. `===`, + * except that `NaN` matches `NaN`. See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {...*} [values] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3, 1, 2, 3]; + * _.pull(array, 2, 3); + * console.log(array); + * // => [1, 1] + */ +function pull() { + var array = arguments[0]; + if (!(array && array.length)) { + return array; + } + var index = 0, + indexOf = baseIndexOf, + length = arguments.length; + + while (++index < length) { + var fromIndex = 0, + value = arguments[index]; + + while ((fromIndex = indexOf(array, value, fromIndex)) > -1) { + splice.call(array, fromIndex, 1); + } + } + return array; +} + +export default pull; diff --git a/array/pullAt.js b/array/pullAt.js new file mode 100644 index 0000000000..14f9fb1266 --- /dev/null +++ b/array/pullAt.js @@ -0,0 +1,33 @@ +import baseFlatten from '../internal/baseFlatten'; +import basePullAt from '../internal/basePullAt'; + +/** + * Removes elements from `array` corresponding to the given indexes and returns + * an array of the removed elements. Indexes may be specified as an array of + * indexes or as individual arguments. + * + * **Note:** Unlike `_.at`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {...(number|number[])} [indexes] The indexes of elements to remove, + * specified as individual indexes or arrays of indexes. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [5, 10, 15, 20]; + * var evens = _.pullAt(array, [1, 3]); + * + * console.log(array); + * // => [5, 15] + * + * console.log(evens); + * // => [10, 20] + */ +function pullAt(array) { + return basePullAt(array || [], baseFlatten(arguments, false, false, 1)); +} + +export default pullAt; diff --git a/array/remove.js b/array/remove.js new file mode 100644 index 0000000000..88830628bb --- /dev/null +++ b/array/remove.js @@ -0,0 +1,60 @@ +import baseCallback from '../internal/baseCallback'; + +/** Used for native method references. */ +var arrayProto = Array.prototype; + +/** Native method references. */ +var splice = arrayProto.splice; + +/** + * Removes all elements from `array` that `predicate` returns truthy for + * and returns an array of the removed elements. The predicate is bound to + * `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * **Note:** Unlike `_.filter`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4]; + * var evens = _.remove(array, function(n) { return n % 2 == 0; }); + * + * console.log(array); + * // => [1, 3] + * + * console.log(evens); + * // => [2, 4] + */ +function remove(array, predicate, thisArg) { + var index = -1, + length = array ? array.length : 0, + result = []; + + predicate = baseCallback(predicate, thisArg, 3); + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + splice.call(array, index--, 1); + length--; + } + } + return result; +} + +export default remove; diff --git a/array/rest.js b/array/rest.js new file mode 100644 index 0000000000..285876cf2b --- /dev/null +++ b/array/rest.js @@ -0,0 +1,21 @@ +import drop from './drop'; + +/** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @alias tail + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.rest([1, 2, 3]); + * // => [2, 3] + */ +function rest(array) { + return drop(array, 1); +} + +export default rest; diff --git a/array/slice.js b/array/slice.js new file mode 100644 index 0000000000..7a3eef56a8 --- /dev/null +++ b/array/slice.js @@ -0,0 +1,30 @@ +import baseSlice from '../internal/baseSlice'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This function is used instead of `Array#slice` to support node + * lists in IE < 9 and to ensure dense arrays are returned. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ +function slice(array, start, end) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; + } + return baseSlice(array, start, end); +} + +export default slice; diff --git a/array/sortedIndex.js b/array/sortedIndex.js new file mode 100644 index 0000000000..b1e4995a88 --- /dev/null +++ b/array/sortedIndex.js @@ -0,0 +1,56 @@ +import baseCallback from '../internal/baseCallback'; +import binaryIndex from '../internal/binaryIndex'; +import binaryIndexBy from '../internal/binaryIndexBy'; + +/** + * Uses a binary search to determine the lowest index at which `value` should + * be inserted into `array` in order to maintain its sort order. If an iteratee + * function is provided it is invoked for `value` and each element of `array` + * to compute their sort ranking. The iteratee is bound to `thisArg` and + * invoked with one argument; (value). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + * + * _.sortedIndex([4, 4, 5, 5, 6, 6], 5); + * // => 2 + * + * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; + * + * // using an iteratee function + * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { + * return this.data[word]; + * }, dict); + * // => 1 + * + * // using the "_.property" callback shorthand + * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); + * // => 1 + */ +function sortedIndex(array, value, iteratee, thisArg) { + return iteratee == null + ? binaryIndex(array, value) + : binaryIndexBy(array, value, baseCallback(iteratee, thisArg, 1)); +} + +export default sortedIndex; diff --git a/array/sortedLastIndex.js b/array/sortedLastIndex.js new file mode 100644 index 0000000000..4a623d46d1 --- /dev/null +++ b/array/sortedLastIndex.js @@ -0,0 +1,32 @@ +import baseCallback from '../internal/baseCallback'; +import binaryIndex from '../internal/binaryIndex'; +import binaryIndexBy from '../internal/binaryIndexBy'; + +/** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedLastIndex([4, 4, 5, 5, 6, 6], 5); + * // => 4 + */ +function sortedLastIndex(array, value, iteratee, thisArg) { + return iteratee == null + ? binaryIndex(array, value, true) + : binaryIndexBy(array, value, baseCallback(iteratee, thisArg, 1), true); +} + +export default sortedLastIndex; diff --git a/array/tail.js b/array/tail.js new file mode 100644 index 0000000000..450e81b131 --- /dev/null +++ b/array/tail.js @@ -0,0 +1,2 @@ +import rest from './rest' +export default rest; diff --git a/array/take.js b/array/take.js new file mode 100644 index 0000000000..cbe87f8499 --- /dev/null +++ b/array/take.js @@ -0,0 +1,40 @@ +import baseSlice from '../internal/baseSlice'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ +function take(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + return baseSlice(array, 0, n < 0 ? 0 : n); +} + +export default take; diff --git a/array/takeRight.js b/array/takeRight.js new file mode 100644 index 0000000000..25eeff60ee --- /dev/null +++ b/array/takeRight.js @@ -0,0 +1,41 @@ +import baseSlice from '../internal/baseSlice'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ +function takeRight(array, n, guard) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + n = length - (+n || 0); + return baseSlice(array, n < 0 ? 0 : n); +} + +export default takeRight; diff --git a/array/takeRightWhile.js b/array/takeRightWhile.js new file mode 100644 index 0000000000..fd131e92fa --- /dev/null +++ b/array/takeRightWhile.js @@ -0,0 +1,54 @@ +import baseCallback from '../internal/baseCallback'; +import baseSlice from '../internal/baseSlice'; + +/** + * Creates a slice of `array` with elements taken from the end. Elements are + * taken until `predicate` returns falsey. The predicate is bound to `thisArg` + * and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per element. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRightWhile([1, 2, 3], function(n) { return n > 1; }); + * // => [2, 3] + * + * var users = [ + * { 'user': 'barney', 'status': 'busy', 'active': false }, + * { 'user': 'fred', 'status': 'busy', 'active': true }, + * { 'user': 'pebbles', 'status': 'away', 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.takeRightWhile(users, 'active'), 'user'); + * // => ['fred', 'pebbles'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.takeRightWhile(users, { 'status': 'away' }), 'user'); + * // => ['pebbles'] + */ +function takeRightWhile(array, predicate, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + predicate = baseCallback(predicate, thisArg, 3); + while (length-- && predicate(array[length], length, array)) {} + return baseSlice(array, length + 1); +} + +export default takeRightWhile; diff --git a/array/takeWhile.js b/array/takeWhile.js new file mode 100644 index 0000000000..c787430400 --- /dev/null +++ b/array/takeWhile.js @@ -0,0 +1,55 @@ +import baseCallback from '../internal/baseCallback'; +import baseSlice from '../internal/baseSlice'; + +/** + * Creates a slice of `array` with elements taken from the beginning. Elements + * are taken until `predicate` returns falsey. The predicate is bound to + * `thisArg` and invoked with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Array + * @param {Array} array The array to query. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per element. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeWhile([1, 2, 3], function(n) { return n < 3; }); + * // => [1, 2] + * + * var users = [ + * { 'user': 'barney', 'status': 'busy', 'active': true }, + * { 'user': 'fred', 'status': 'busy', 'active': false }, + * { 'user': 'pebbles', 'status': 'away', 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.takeWhile(users, 'active'), 'user'); + * // => ['barney'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.takeWhile(users, { 'status': 'busy' }), 'user'); + * // => ['barney', 'fred'] + */ +function takeWhile(array, predicate, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + var index = -1; + predicate = baseCallback(predicate, thisArg, 3); + while (++index < length && predicate(array[index], index, array)) {} + return baseSlice(array, 0, index); +} + +export default takeWhile; diff --git a/array/union.js b/array/union.js new file mode 100644 index 0000000000..c785873f06 --- /dev/null +++ b/array/union.js @@ -0,0 +1,27 @@ +import baseFlatten from '../internal/baseFlatten'; +import baseUniq from '../internal/baseUniq'; + +/** + * Creates an array of unique values, in order, of the provided arrays using + * `SameValueZero` for equality comparisons. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]); + * // => [1, 2, 3, 5, 4] + */ +function union() { + return baseUniq(baseFlatten(arguments, false, true)); +} + +export default union; diff --git a/array/uniq.js b/array/uniq.js new file mode 100644 index 0000000000..1e53b2fd1b --- /dev/null +++ b/array/uniq.js @@ -0,0 +1,71 @@ +import baseCallback from '../internal/baseCallback'; +import baseUniq from '../internal/baseUniq'; +import isIterateeCall from '../internal/isIterateeCall'; +import sortedUniq from '../internal/sortedUniq'; + +/** + * Creates a duplicate-value-free version of an array using `SameValueZero` + * for equality comparisons. Providing `true` for `isSorted` performs a faster + * search algorithm for sorted arrays. If an iteratee function is provided it + * is invoked for each value in the array to generate the criterion by which + * uniqueness is computed. The `iteratee` is bound to `thisArg` and invoked + * with three arguments; (value, index, array). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @alias unique + * @category Array + * @param {Array} array The array to inspect. + * @param {boolean} [isSorted] Specify the array is sorted. + * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * If a property name or object is provided it is used to create a "_.property" + * or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new duplicate-value-free array. + * @example + * + * _.uniq([1, 2, 1]); + * // => [1, 2] + * + * // using `isSorted` + * _.uniq([1, 1, 2], true); + * // => [1, 2] + * + * // using an iteratee function + * _.uniq([1, 2.5, 1.5, 2], function(n) { return this.floor(n); }, Math); + * // => [1, 2.5] + * + * // using the "_.property" callback shorthand + * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ +function uniq(array, isSorted, iteratee, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + // Juggle arguments. + if (typeof isSorted != 'boolean' && isSorted != null) { + thisArg = iteratee; + iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted; + isSorted = false; + } + iteratee = iteratee == null ? iteratee : baseCallback(iteratee, thisArg, 3); + return (isSorted) + ? sortedUniq(array, iteratee) + : baseUniq(array, iteratee); +} + +export default uniq; diff --git a/array/unique.js b/array/unique.js new file mode 100644 index 0000000000..bca50d3cdf --- /dev/null +++ b/array/unique.js @@ -0,0 +1,2 @@ +import uniq from './uniq' +export default uniq; diff --git a/array/unzip.js b/array/unzip.js new file mode 100644 index 0000000000..dfdb4701c1 --- /dev/null +++ b/array/unzip.js @@ -0,0 +1,37 @@ +import arrayMap from '../internal/arrayMap'; +import arrayMax from '../internal/arrayMax'; +import baseProperty from '../internal/baseProperty'; + +/** Used to the length of n-tuples for `_.unzip`. */ +var getLength = baseProperty('length'); + +/** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-`_.zip` + * configuration. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] + * + * _.unzip(zipped); + * // => [['fred', 'barney'], [30, 40], [true, false]] + */ +function unzip(array) { + var index = -1, + length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0, + result = Array(length); + + while (++index < length) { + result[index] = arrayMap(array, baseProperty(index)); + } + return result; +} + +export default unzip; diff --git a/array/without.js b/array/without.js new file mode 100644 index 0000000000..7423a99e23 --- /dev/null +++ b/array/without.js @@ -0,0 +1,28 @@ +import baseDifference from '../internal/baseDifference'; +import baseSlice from '../internal/baseSlice'; + +/** + * Creates an array excluding all provided values using `SameValueZero` for + * equality comparisons. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to filter. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); + * // => [2, 3, 4] + */ +function without(array) { + return baseDifference(array, baseSlice(arguments, 1)); +} + +export default without; diff --git a/array/xor.js b/array/xor.js new file mode 100644 index 0000000000..aa5d7a6f22 --- /dev/null +++ b/array/xor.js @@ -0,0 +1,39 @@ +import baseDifference from '../internal/baseDifference'; +import baseUniq from '../internal/baseUniq'; +import isArguments from '../lang/isArguments'; +import isArray from '../lang/isArray'; + +/** + * Creates an array that is the symmetric difference of the provided arrays. + * See [Wikipedia](https://en.wikipedia.org/wiki/Symmetric_difference) for + * more details. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of values. + * @example + * + * _.xor([1, 2, 3], [5, 2, 1, 4]); + * // => [3, 5, 4] + * + * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]); + * // => [1, 4, 5] + */ +function xor() { + var index = -1, + length = arguments.length; + + while (++index < length) { + var array = arguments[index]; + if (isArray(array) || isArguments(array)) { + var result = result + ? baseDifference(result, array).concat(baseDifference(array, result)) + : array; + } + } + return result ? baseUniq(result) : []; +} + +export default xor; diff --git a/array/zip.js b/array/zip.js new file mode 100644 index 0000000000..168a066140 --- /dev/null +++ b/array/zip.js @@ -0,0 +1,28 @@ +import unzip from './unzip'; + +/** + * Creates an array of grouped elements, the first of which contains the first + * elements of the given arrays, the second of which contains the second elements + * of the given arrays, and so on. + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] + */ +function zip() { + var length = arguments.length, + array = Array(length); + + while (length--) { + array[length] = arguments[length]; + } + return unzip(array); +} + +export default zip; diff --git a/array/zipObject.js b/array/zipObject.js new file mode 100644 index 0000000000..f7218e8409 --- /dev/null +++ b/array/zipObject.js @@ -0,0 +1,39 @@ +import isArray from '../lang/isArray'; + +/** + * Creates an object composed from arrays of property names and values. Provide + * either a single two dimensional array, e.g. `[[key1, value1], [key2, value2]]` + * or two arrays, one of property names and one of corresponding values. + * + * @static + * @memberOf _ + * @alias object + * @category Array + * @param {Array} props The property names. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject(['fred', 'barney'], [30, 40]); + * // => { 'fred': 30, 'barney': 40 } + */ +function zipObject(props, values) { + var index = -1, + length = props ? props.length : 0, + result = {}; + + if (length && !values && !isArray(props[0])) { + values = []; + } + while (++index < length) { + var key = props[index]; + if (values) { + result[key] = values[index]; + } else if (key) { + result[key[0]] = key[1]; + } + } + return result; +} + +export default zipObject; diff --git a/chain.js b/chain.js new file mode 100644 index 0000000000..1480ba20d1 --- /dev/null +++ b/chain.js @@ -0,0 +1,23 @@ +import chain from './chain/chain'; +import lodash from './chain/lodash'; +import reverse from './chain/reverse'; +import tap from './chain/tap'; +import thru from './chain/thru'; +import toJSON from './chain/toJSON'; +import toString from './chain/toString'; +import value from './chain/value'; +import valueOf from './chain/valueOf'; +import wrapperChain from './chain/wrapperChain'; + +export default { + 'chain': chain, + 'lodash': lodash, + 'reverse': reverse, + 'tap': tap, + 'thru': thru, + 'toJSON': toJSON, + 'toString': toString, + 'value': value, + 'valueOf': valueOf, + 'wrapperChain': wrapperChain +}; diff --git a/chain/chain.js b/chain/chain.js new file mode 100644 index 0000000000..dde9cb2d16 --- /dev/null +++ b/chain/chain.js @@ -0,0 +1,33 @@ +import lodash from './lodash'; + +/** + * Creates a `lodash` object that wraps `value` with explicit method + * chaining enabled. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` object. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _.chain(users) + * .sortBy('age') + * .map(function(chr) { return chr.user + ' is ' + chr.age; }) + * .first() + * .value(); + * // => 'pebbles is 1' + */ +function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; +} + +export default chain; diff --git a/chain/lodash.js b/chain/lodash.js new file mode 100644 index 0000000000..452e9284d0 --- /dev/null +++ b/chain/lodash.js @@ -0,0 +1,109 @@ +import LodashWrapper from '../internal/LodashWrapper'; +import arrayCopy from '../internal/arrayCopy'; +import isArray from '../lang/isArray'; +import isObjectLike from '../internal/isObjectLike'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Creates a `lodash` object which wraps `value` to enable intuitive chaining. + * Methods that operate on and return arrays, collections, and functions can + * be chained together. Methods that return a boolean or single value will + * automatically end the chain returning the unwrapped value. Explicit chaining + * may be enabled using `_.chain`. The execution of chained methods is lazy, + * that is, execution is deferred until `_#value` is implicitly or explicitly + * called. + * + * Lazy evaluation allows several methods to support shortcut fusion. Shortcut + * fusion is an optimization that merges iteratees to avoid creating intermediate + * arrays and reduce the number of iteratee executions. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers also have the following `Array` methods: + * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`, + * and `unshift` + * + * The wrapper functions that support shortcut fusion are: + * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `first`, + * `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, `slice`, + * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `where` + * + * The chainable wrapper functions are: + * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, + * `callback`, `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`, + * `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`, + * `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`, + * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`, + * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`, + * `initial`, `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`, + * `mapValues`, `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`, + * `omit`, `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`, + * `pluck`, `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`, + * `rearg`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, + * `sortBy`, `sortByAll`, `splice`, `take`, `takeRight`, `takeRightWhile`, + * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, + * `transform`, `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`, + * `where`, `without`, `wrap`, `xor`, `zip`, and `zipObject` + * + * The wrapper functions that are **not** chainable by default are: + * `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`, + * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, + * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`, + * `identity`, `includes`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, + * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite`, + * `isFunction`, `isMatch` , `isNative`, `isNaN`, `isNull`, `isNumber`, + * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, + * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`, + * `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, + * `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`, + * `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, + * `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, + * `unescape`, `uniqueId`, `value`, and `words` + * + * The wrapper function `sample` will return a wrapped value when `n` is provided, + * otherwise an unwrapped value is returned. + * + * @name _ + * @constructor + * @category Chain + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns a `lodash` instance. + * @example + * + * var wrapped = _([1, 2, 3]); + * + * // returns an unwrapped value + * wrapped.reduce(function(sum, n) { return sum + n; }); + * // => 6 + * + * // returns a wrapped value + * var squares = wrapped.map(function(n) { return n * n; }); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ +function lodash(value) { + if (isObjectLike(value) && !isArray(value)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__wrapped__')) { + return new LodashWrapper(value.__wrapped__, value.__chain__, arrayCopy(value.__actions__)); + } + } + return new LodashWrapper(value); +} + +// Ensure `new LodashWrapper` is an instance of `lodash`. +LodashWrapper.prototype = lodash.prototype; + +export default lodash; diff --git a/chain/reverse.js b/chain/reverse.js new file mode 100644 index 0000000000..5602fa2869 --- /dev/null +++ b/chain/reverse.js @@ -0,0 +1,2 @@ +import wrapperReverse from './wrapperReverse' +export default wrapperReverse; diff --git a/chain/tap.js b/chain/tap.js new file mode 100644 index 0000000000..930232fbe8 --- /dev/null +++ b/chain/tap.js @@ -0,0 +1,27 @@ +/** + * This method invokes `interceptor` and returns `value`. The interceptor is + * bound to `thisArg` and invoked with one argument; (value). The purpose of + * this method is to "tap into" a method chain in order to perform operations + * on intermediate results within the chain. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @param {*} [thisArg] The `this` binding of `interceptor`. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { array.pop(); }) + * .reverse() + * .value(); + * // => [2, 1] + */ +function tap(value, interceptor, thisArg) { + interceptor.call(thisArg, value); + return value; +} + +export default tap; diff --git a/chain/thru.js b/chain/thru.js new file mode 100644 index 0000000000..e6258f1630 --- /dev/null +++ b/chain/thru.js @@ -0,0 +1,23 @@ +/** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * + * @static + * @memberOf _ + * @category Chain + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @param {*} [thisArg] The `this` binding of `interceptor`. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _([1, 2, 3]) + * .last() + * .thru(function(value) { return [value]; }) + * .value(); + * // => [3] + */ +function thru(value, interceptor, thisArg) { + return interceptor.call(thisArg, value); +} + +export default thru; diff --git a/chain/toJSON.js b/chain/toJSON.js new file mode 100644 index 0000000000..59ae6ce2a5 --- /dev/null +++ b/chain/toJSON.js @@ -0,0 +1,2 @@ +import wrapperValue from './wrapperValue' +export default wrapperValue; diff --git a/chain/toString.js b/chain/toString.js new file mode 100644 index 0000000000..2600cac237 --- /dev/null +++ b/chain/toString.js @@ -0,0 +1,2 @@ +import wrapperToString from './wrapperToString' +export default wrapperToString; diff --git a/chain/value.js b/chain/value.js new file mode 100644 index 0000000000..59ae6ce2a5 --- /dev/null +++ b/chain/value.js @@ -0,0 +1,2 @@ +import wrapperValue from './wrapperValue' +export default wrapperValue; diff --git a/chain/valueOf.js b/chain/valueOf.js new file mode 100644 index 0000000000..59ae6ce2a5 --- /dev/null +++ b/chain/valueOf.js @@ -0,0 +1,2 @@ +import wrapperValue from './wrapperValue' +export default wrapperValue; diff --git a/chain/wrapperChain.js b/chain/wrapperChain.js new file mode 100644 index 0000000000..819873b172 --- /dev/null +++ b/chain/wrapperChain.js @@ -0,0 +1,32 @@ +import chain from './chain'; + +/** + * Enables explicit method chaining on the wrapper object. + * + * @name chain + * @memberOf _ + * @category Chain + * @returns {*} Returns the `lodash` object. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // without explicit chaining + * _(users).first(); + * // => { 'user': 'barney', 'age': 36 } + * + * // with explicit chaining + * _(users).chain() + * .first() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ +function wrapperChain() { + return chain(this); +} + +export default wrapperChain; diff --git a/chain/wrapperReverse.js b/chain/wrapperReverse.js new file mode 100644 index 0000000000..2f95f30a38 --- /dev/null +++ b/chain/wrapperReverse.js @@ -0,0 +1,35 @@ +import LazyWrapper from '../internal/LazyWrapper'; +import LodashWrapper from '../internal/LodashWrapper'; +import thru from './thru'; + +/** + * Reverses the wrapped array so the first element becomes the last, the + * second element becomes the second to last, and so on. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @category Chain + * @returns {Object} Returns the new reversed `lodash` object. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ +function wrapperReverse() { + var value = this.__wrapped__; + if (value instanceof LazyWrapper) { + return new LodashWrapper(value.reverse()); + } + return this.thru(function(value) { + return value.reverse(); + }); +} + +export default wrapperReverse; diff --git a/chain/wrapperToString.js b/chain/wrapperToString.js new file mode 100644 index 0000000000..21f6db4a5c --- /dev/null +++ b/chain/wrapperToString.js @@ -0,0 +1,17 @@ +/** + * Produces the result of coercing the unwrapped value to a string. + * + * @name toString + * @memberOf _ + * @category Chain + * @returns {string} Returns the coerced string value. + * @example + * + * _([1, 2, 3]).toString(); + * // => '1,2,3' + */ +function wrapperToString() { + return (this.value() + ''); +} + +export default wrapperToString; diff --git a/chain/wrapperValue.js b/chain/wrapperValue.js new file mode 100644 index 0000000000..eeeb58ac56 --- /dev/null +++ b/chain/wrapperValue.js @@ -0,0 +1,20 @@ +import baseWrapperValue from '../internal/baseWrapperValue'; + +/** + * Executes the chained sequence to extract the unwrapped value. + * + * @name value + * @memberOf _ + * @alias toJSON, valueOf + * @category Chain + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ +function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); +} + +export default wrapperValue; diff --git a/collection.js b/collection.js new file mode 100644 index 0000000000..351c74573b --- /dev/null +++ b/collection.js @@ -0,0 +1,83 @@ +import all from './collection/all'; +import any from './collection/any'; +import at from './collection/at'; +import collect from './collection/collect'; +import contains from './collection/contains'; +import countBy from './collection/countBy'; +import detect from './collection/detect'; +import each from './collection/each'; +import eachRight from './collection/eachRight'; +import every from './collection/every'; +import filter from './collection/filter'; +import find from './collection/find'; +import findLast from './collection/findLast'; +import findWhere from './collection/findWhere'; +import foldl from './collection/foldl'; +import foldr from './collection/foldr'; +import forEach from './collection/forEach'; +import forEachRight from './collection/forEachRight'; +import groupBy from './collection/groupBy'; +import include from './collection/include'; +import includes from './collection/includes'; +import indexBy from './collection/indexBy'; +import inject from './collection/inject'; +import invoke from './collection/invoke'; +import map from './collection/map'; +import max from './collection/max'; +import min from './collection/min'; +import partition from './collection/partition'; +import pluck from './collection/pluck'; +import reduce from './collection/reduce'; +import reduceRight from './collection/reduceRight'; +import reject from './collection/reject'; +import sample from './collection/sample'; +import select from './collection/select'; +import shuffle from './collection/shuffle'; +import size from './collection/size'; +import some from './collection/some'; +import sortBy from './collection/sortBy'; +import sortByAll from './collection/sortByAll'; +import where from './collection/where'; + +export default { + 'all': all, + 'any': any, + 'at': at, + 'collect': collect, + 'contains': contains, + 'countBy': countBy, + 'detect': detect, + 'each': each, + 'eachRight': eachRight, + 'every': every, + 'filter': filter, + 'find': find, + 'findLast': findLast, + 'findWhere': findWhere, + 'foldl': foldl, + 'foldr': foldr, + 'forEach': forEach, + 'forEachRight': forEachRight, + 'groupBy': groupBy, + 'include': include, + 'includes': includes, + 'indexBy': indexBy, + 'inject': inject, + 'invoke': invoke, + 'map': map, + 'max': max, + 'min': min, + 'partition': partition, + 'pluck': pluck, + 'reduce': reduce, + 'reduceRight': reduceRight, + 'reject': reject, + 'sample': sample, + 'select': select, + 'shuffle': shuffle, + 'size': size, + 'some': some, + 'sortBy': sortBy, + 'sortByAll': sortByAll, + 'where': where +}; diff --git a/collection/all.js b/collection/all.js new file mode 100644 index 0000000000..723b5f8e51 --- /dev/null +++ b/collection/all.js @@ -0,0 +1,2 @@ +import every from './every' +export default every; diff --git a/collection/any.js b/collection/any.js new file mode 100644 index 0000000000..2da88029b8 --- /dev/null +++ b/collection/any.js @@ -0,0 +1,2 @@ +import some from './some' +export default some; diff --git a/collection/at.js b/collection/at.js new file mode 100644 index 0000000000..4ee46c828c --- /dev/null +++ b/collection/at.js @@ -0,0 +1,34 @@ +import baseAt from '../internal/baseAt'; +import baseFlatten from '../internal/baseFlatten'; +import isLength from '../internal/isLength'; +import toIterable from '../internal/toIterable'; + +/** + * Creates an array of elements corresponding to the given keys, or indexes, + * of `collection`. Keys may be specified as individual arguments or as arrays + * of keys. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(number|number[]|string|string[])} [props] The property names + * or indexes of elements to pick, specified individually or in arrays. + * @returns {Array} Returns the new array of picked elements. + * @example + * + * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); + * // => ['a', 'c', 'e'] + * + * _.at(['fred', 'barney', 'pebbles'], 0, 2); + * // => ['fred', 'pebbles'] + */ +function at(collection) { + var length = collection ? collection.length : 0; + if (isLength(length)) { + collection = toIterable(collection); + } + return baseAt(collection, baseFlatten(arguments, false, false, 1)); +} + +export default at; diff --git a/collection/collect.js b/collection/collect.js new file mode 100644 index 0000000000..982f50a4c5 --- /dev/null +++ b/collection/collect.js @@ -0,0 +1,2 @@ +import map from './map' +export default map; diff --git a/collection/contains.js b/collection/contains.js new file mode 100644 index 0000000000..a1520e467a --- /dev/null +++ b/collection/contains.js @@ -0,0 +1,2 @@ +import includes from './includes' +export default includes; diff --git a/collection/countBy.js b/collection/countBy.js new file mode 100644 index 0000000000..0181a1327a --- /dev/null +++ b/collection/countBy.js @@ -0,0 +1,47 @@ +import createAggregator from '../internal/createAggregator'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is the number of times the key was returned by `iteratee`. + * The `iteratee` is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([4.3, 6.1, 6.4], function(n) { return Math.floor(n); }); + * // => { '4': 1, '6': 2 } + * + * _.countBy([4.3, 6.1, 6.4], function(n) { return this.floor(n); }, Math); + * // => { '4': 1, '6': 2 } + * + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ +var countBy = createAggregator(function(result, value, key) { + hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1); +}); + +export default countBy; diff --git a/collection/detect.js b/collection/detect.js new file mode 100644 index 0000000000..3496fdc3ef --- /dev/null +++ b/collection/detect.js @@ -0,0 +1,2 @@ +import find from './find' +export default find; diff --git a/collection/each.js b/collection/each.js new file mode 100644 index 0000000000..182b7b7097 --- /dev/null +++ b/collection/each.js @@ -0,0 +1,2 @@ +import forEach from './forEach' +export default forEach; diff --git a/collection/eachRight.js b/collection/eachRight.js new file mode 100644 index 0000000000..24047ca099 --- /dev/null +++ b/collection/eachRight.js @@ -0,0 +1,2 @@ +import forEachRight from './forEachRight' +export default forEachRight; diff --git a/collection/every.js b/collection/every.js new file mode 100644 index 0000000000..75f57cf898 --- /dev/null +++ b/collection/every.js @@ -0,0 +1,55 @@ +import arrayEvery from '../internal/arrayEvery'; +import baseCallback from '../internal/baseCallback'; +import baseEvery from '../internal/baseEvery'; +import isArray from '../lang/isArray'; + +/** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * The predicate is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias all + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes']); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // using the "_.property" callback shorthand + * _.every(users, 'age'); + * // => true + * + * // using the "_.matches" callback shorthand + * _.every(users, { 'age': 36 }); + * // => false + */ +function every(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (typeof predicate != 'function' || typeof thisArg != 'undefined') { + predicate = baseCallback(predicate, thisArg, 3); + } + return func(collection, predicate); +} + +export default every; diff --git a/collection/filter.js b/collection/filter.js new file mode 100644 index 0000000000..660fddfbb1 --- /dev/null +++ b/collection/filter.js @@ -0,0 +1,52 @@ +import arrayFilter from '../internal/arrayFilter'; +import baseCallback from '../internal/baseCallback'; +import baseFilter from '../internal/baseFilter'; +import isArray from '../lang/isArray'; + +/** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias select + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new filtered array. + * @example + * + * var evens = _.filter([1, 2, 3, 4], function(n) { return n % 2 == 0; }); + * // => [2, 4] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.filter(users, 'active'), 'user'); + * // => ['fred'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.filter(users, { 'age': 36 }), 'user'); + * // => ['barney'] + */ +function filter(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayFilter : baseFilter; + predicate = baseCallback(predicate, thisArg, 3); + return func(collection, predicate); +} + +export default filter; diff --git a/collection/find.js b/collection/find.js new file mode 100644 index 0000000000..73b289f024 --- /dev/null +++ b/collection/find.js @@ -0,0 +1,57 @@ +import baseCallback from '../internal/baseCallback'; +import baseEach from '../internal/baseEach'; +import baseFind from '../internal/baseFind'; +import findIndex from '../array/findIndex'; +import isArray from '../lang/isArray'; + +/** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias detect + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.result(_.find(users, function(chr) { return chr.age < 40; }), 'user'); + * // => 'barney' + * + * // using the "_.matches" callback shorthand + * _.result(_.find(users, { 'age': 1 }), 'user'); + * // => 'pebbles' + * + * // using the "_.property" callback shorthand + * _.result(_.find(users, 'active'), 'user'); + * // => 'fred' + */ +function find(collection, predicate, thisArg) { + if (isArray(collection)) { + var index = findIndex(collection, predicate, thisArg); + return index > -1 ? collection[index] : undefined; + } + predicate = baseCallback(predicate, thisArg, 3); + return baseFind(collection, predicate, baseEach); +} + +export default find; diff --git a/collection/findLast.js b/collection/findLast.js new file mode 100644 index 0000000000..58ba6f508b --- /dev/null +++ b/collection/findLast.js @@ -0,0 +1,28 @@ +import baseCallback from '../internal/baseCallback'; +import baseEachRight from '../internal/baseEachRight'; +import baseFind from '../internal/baseFind'; + +/** + * This method is like `_.find` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(n) { return n % 2 == 1; }); + * // => 3 + */ +function findLast(collection, predicate, thisArg) { + predicate = baseCallback(predicate, thisArg, 3); + return baseFind(collection, predicate, baseEachRight); +} + +export default findLast; diff --git a/collection/findWhere.js b/collection/findWhere.js new file mode 100644 index 0000000000..acf0ae0496 --- /dev/null +++ b/collection/findWhere.js @@ -0,0 +1,32 @@ +import find from './find'; +import matches from '../utility/matches'; + +/** + * Performs a deep comparison between each element in `collection` and the + * source object, returning the first element that has equivalent property + * values. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'status': 'busy' }, + * { 'user': 'fred', 'age': 40, 'status': 'busy' } + * ]; + * + * _.result(_.findWhere(users, { 'status': 'busy' }), 'user'); + * // => 'barney' + * + * _.result(_.findWhere(users, { 'age': 40 }), 'user'); + * // => 'fred' + */ +function findWhere(collection, source) { + return find(collection, matches(source)); +} + +export default findWhere; diff --git a/collection/foldl.js b/collection/foldl.js new file mode 100644 index 0000000000..83cfab7726 --- /dev/null +++ b/collection/foldl.js @@ -0,0 +1,2 @@ +import reduce from './reduce' +export default reduce; diff --git a/collection/foldr.js b/collection/foldr.js new file mode 100644 index 0000000000..cbd7db3fa7 --- /dev/null +++ b/collection/foldr.js @@ -0,0 +1,2 @@ +import reduceRight from './reduceRight' +export default reduceRight; diff --git a/collection/forEach.js b/collection/forEach.js new file mode 100644 index 0000000000..b318a1d104 --- /dev/null +++ b/collection/forEach.js @@ -0,0 +1,38 @@ +import arrayEach from '../internal/arrayEach'; +import baseEach from '../internal/baseEach'; +import bindCallback from '../internal/bindCallback'; +import isArray from '../lang/isArray'; + +/** + * Iterates over elements of `collection` invoking `iteratee` for each element. + * The `iteratee` is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). Iterator functions may exit iteration early + * by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a `length` property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * + * @static + * @memberOf _ + * @alias each + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2, 3]).forEach(function(n) { console.log(n); }); + * // => logs each value from left to right and returns the array + * + * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(n, key) { console.log(n, key); }); + * // => logs each value-key pair and returns the object (iteration order is not guaranteed) + */ +function forEach(collection, iteratee, thisArg) { + return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection)) + ? arrayEach(collection, iteratee) + : baseEach(collection, bindCallback(iteratee, thisArg, 3)); +} + +export default forEach; diff --git a/collection/forEachRight.js b/collection/forEachRight.js new file mode 100644 index 0000000000..a0a5996706 --- /dev/null +++ b/collection/forEachRight.js @@ -0,0 +1,29 @@ +import arrayEachRight from '../internal/arrayEachRight'; +import baseEachRight from '../internal/baseEachRight'; +import bindCallback from '../internal/bindCallback'; +import isArray from '../lang/isArray'; + +/** + * This method is like `_.forEach` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @alias eachRight + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2, 3]).forEachRight(function(n) { console.log(n); }).join(','); + * // => logs each value from right to left and returns the array + */ +function forEachRight(collection, iteratee, thisArg) { + return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection)) + ? arrayEachRight(collection, iteratee) + : baseEachRight(collection, bindCallback(iteratee, thisArg, 3)); +} + +export default forEachRight; diff --git a/collection/groupBy.js b/collection/groupBy.js new file mode 100644 index 0000000000..ac7ff3836b --- /dev/null +++ b/collection/groupBy.js @@ -0,0 +1,52 @@ +import createAggregator from '../internal/createAggregator'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is an array of the elements responsible for generating the key. + * The `iteratee` is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([4.2, 6.1, 6.4], function(n) { return Math.floor(n); }); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * _.groupBy([4.2, 6.1, 6.4], function(n) { return this.floor(n); }, Math); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * // using the "_.property" callback shorthand + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ +var groupBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + result[key] = [value]; + } +}); + +export default groupBy; diff --git a/collection/include.js b/collection/include.js new file mode 100644 index 0000000000..a1520e467a --- /dev/null +++ b/collection/include.js @@ -0,0 +1,2 @@ +import includes from './includes' +export default includes; diff --git a/collection/includes.js b/collection/includes.js new file mode 100644 index 0000000000..8eea3a6561 --- /dev/null +++ b/collection/includes.js @@ -0,0 +1,61 @@ +import baseIndexOf from '../internal/baseIndexOf'; +import isArray from '../lang/isArray'; +import isLength from '../internal/isLength'; +import isString from '../lang/isString'; +import values from '../object/values'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * Checks if `value` is in `collection` using `SameValueZero` for equality + * comparisons. If `fromIndex` is negative, it is used as the offset from + * the end of `collection`. + * + * **Note:** `SameValueZero` comparisons are like strict equality comparisons, + * e.g. `===`, except that `NaN` matches `NaN`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) + * for more details. + * + * @static + * @memberOf _ + * @alias contains, include + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {*} target The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {boolean} Returns `true` if a matching element is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); + * // => true + * + * _.includes('pebbles', 'eb'); + * // => true + */ +function includes(collection, target, fromIndex) { + var length = collection ? collection.length : 0; + if (!isLength(length)) { + collection = values(collection); + length = collection.length; + } + if (!length) { + return false; + } + if (typeof fromIndex == 'number') { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); + } else { + fromIndex = 0; + } + return (typeof collection == 'string' || !isArray(collection) && isString(collection)) + ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1) + : (baseIndexOf(collection, target, fromIndex) > -1); +} + +export default includes; diff --git a/collection/indexBy.js b/collection/indexBy.js new file mode 100644 index 0000000000..fbf9b2386c --- /dev/null +++ b/collection/indexBy.js @@ -0,0 +1,46 @@ +import createAggregator from '../internal/createAggregator'; + +/** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is the last element responsible for generating the key. The + * iteratee function is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var keyData = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.indexBy(keyData, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keyData, function(object) { return String.fromCharCode(object.code); }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keyData, function(object) { return this.fromCharCode(object.code); }, String); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + */ +var indexBy = createAggregator(function(result, value, key) { + result[key] = value; +}); + +export default indexBy; diff --git a/collection/inject.js b/collection/inject.js new file mode 100644 index 0000000000..83cfab7726 --- /dev/null +++ b/collection/inject.js @@ -0,0 +1,2 @@ +import reduce from './reduce' +export default reduce; diff --git a/collection/invoke.js b/collection/invoke.js new file mode 100644 index 0000000000..ebe0c41594 --- /dev/null +++ b/collection/invoke.js @@ -0,0 +1,30 @@ +import baseInvoke from '../internal/baseInvoke'; +import baseSlice from '../internal/baseSlice'; + +/** + * Invokes the method named by `methodName` on each element in `collection`, + * returning an array of the results of each invoked method. Any additional + * arguments are provided to each invoked method. If `methodName` is a function + * it is invoked for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|string} methodName The name of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invoke([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ +function invoke(collection, methodName) { + return baseInvoke(collection, methodName, baseSlice(arguments, 2)); +} + +export default invoke; diff --git a/collection/map.js b/collection/map.js new file mode 100644 index 0000000000..28bd143424 --- /dev/null +++ b/collection/map.js @@ -0,0 +1,51 @@ +import arrayMap from '../internal/arrayMap'; +import baseCallback from '../internal/baseCallback'; +import baseMap from '../internal/baseMap'; +import isArray from '../lang/isArray'; + +/** + * Creates an array of values by running each element in `collection` through + * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three + * arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias collect + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new mapped array. + * @example + * + * _.map([1, 2, 3], function(n) { return n * 3; }); + * // => [3, 6, 9] + * + * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(n) { return n * 3; }); + * // => [3, 6, 9] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // using the "_.property" callback shorthand + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ +function map(collection, iteratee, thisArg) { + var func = isArray(collection) ? arrayMap : baseMap; + iteratee = baseCallback(iteratee, thisArg, 3); + return func(collection, iteratee); +} + +export default map; diff --git a/collection/max.js b/collection/max.js new file mode 100644 index 0000000000..56d9f865b6 --- /dev/null +++ b/collection/max.js @@ -0,0 +1,49 @@ +import arrayMax from '../internal/arrayMax'; +import createExtremum from '../internal/createExtremum'; + +/** + * Gets the maximum value of `collection`. If `collection` is empty or falsey + * `-Infinity` is returned. If an iteratee function is provided it is invoked + * for each value in `collection` to generate the criterion by which the value + * is ranked. The `iteratee` is bound to `thisArg` and invoked with three + * arguments; (value, index, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * If a property name or object is provided it is used to create a "_.property" + * or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the maximum value. + * @example + * + * _.max([4, 2, 8, 6]); + * // => 8 + * + * _.max([]); + * // => -Infinity + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.max(users, function(chr) { return chr.age; }); + * // => { 'user': 'fred', 'age': 40 }; + * + * // using the "_.property" callback shorthand + * _.max(users, 'age'); + * // => { 'user': 'fred', 'age': 40 }; + */ +var max = createExtremum(arrayMax); + +export default max; diff --git a/collection/min.js b/collection/min.js new file mode 100644 index 0000000000..70e43a3a86 --- /dev/null +++ b/collection/min.js @@ -0,0 +1,49 @@ +import arrayMin from '../internal/arrayMin'; +import createExtremum from '../internal/createExtremum'; + +/** + * Gets the minimum value of `collection`. If `collection` is empty or falsey + * `Infinity` is returned. If an iteratee function is provided it is invoked + * for each value in `collection` to generate the criterion by which the value + * is ranked. The `iteratee` is bound to `thisArg` and invoked with three + * arguments; (value, index, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * If a property name or object is provided it is used to create a "_.property" + * or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the minimum value. + * @example + * + * _.min([4, 2, 8, 6]); + * // => 2 + * + * _.min([]); + * // => Infinity + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.min(users, function(chr) { return chr.age; }); + * // => { 'user': 'barney', 'age': 36 }; + * + * // using the "_.property" callback shorthand + * _.min(users, 'age'); + * // => { 'user': 'barney', 'age': 36 }; + */ +var min = createExtremum(arrayMin, true); + +export default min; diff --git a/collection/partition.js b/collection/partition.js new file mode 100644 index 0000000000..21517417f0 --- /dev/null +++ b/collection/partition.js @@ -0,0 +1,51 @@ +import createAggregator from '../internal/createAggregator'; + +/** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, while the second of which + * contains elements `predicate` returns falsey for. The predicate is bound + * to `thisArg` and invoked with three arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * _.partition([1, 2, 3], function(n) { return n % 2; }); + * // => [[1, 3], [2]] + * + * _.partition([1.2, 2.3, 3.4], function(n) { return this.floor(n) % 2; }, Math); + * // => [[1, 3], [2]] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * // using the "_.matches" callback shorthand + * _.map(_.partition(users, { 'age': 1 }), function(array) { return _.pluck(array, 'user'); }); + * // => [['pebbles'], ['barney', 'fred']] + * + * // using the "_.property" callback shorthand + * _.map(_.partition(users, 'active'), function(array) { return _.pluck(array, 'user'); }); + * // => [['fred'], ['barney', 'pebbles']] + */ +var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); +}, function() { return [[], []]; }); + +export default partition; diff --git a/collection/pluck.js b/collection/pluck.js new file mode 100644 index 0000000000..5d8b004a11 --- /dev/null +++ b/collection/pluck.js @@ -0,0 +1,31 @@ +import map from './map'; +import property from '../utility/property'; + +/** + * Gets the value of `key` from all elements in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {string} key The key of the property to pluck. + * @returns {Array} Returns the property values. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.pluck(users, 'user'); + * // => ['barney', 'fred'] + * + * var userIndex = _.indexBy(users, 'user'); + * _.pluck(userIndex, 'age'); + * // => [36, 40] (iteration order is not guaranteed) + */ +function pluck(collection, key) { + return map(collection, property(key)); +} + +export default pluck; diff --git a/collection/reduce.js b/collection/reduce.js new file mode 100644 index 0000000000..c19dce38a4 --- /dev/null +++ b/collection/reduce.js @@ -0,0 +1,40 @@ +import arrayReduce from '../internal/arrayReduce'; +import baseCallback from '../internal/baseCallback'; +import baseEach from '../internal/baseEach'; +import baseReduce from '../internal/baseReduce'; +import isArray from '../lang/isArray'; + +/** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` through `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not provided the first element of `collection` is used as the initial + * value. The `iteratee` is bound to `thisArg`and invoked with four arguments; + * (accumulator, value, index|key, collection). + * + * @static + * @memberOf _ + * @alias foldl, inject + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * var sum = _.reduce([1, 2, 3], function(sum, n) { return sum + n; }); + * // => 6 + * + * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) { + * result[key] = n * 3; + * return result; + * }, {}); + * // => { 'a': 3, 'b': 6, 'c': 9 } (iteration order is not guaranteed) + */ +function reduce(collection, iteratee, accumulator, thisArg) { + var func = isArray(collection) ? arrayReduce : baseReduce; + return func(collection, baseCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEach); +} + +export default reduce; diff --git a/collection/reduceRight.js b/collection/reduceRight.js new file mode 100644 index 0000000000..d1c29f5a2c --- /dev/null +++ b/collection/reduceRight.js @@ -0,0 +1,31 @@ +import arrayReduceRight from '../internal/arrayReduceRight'; +import baseCallback from '../internal/baseCallback'; +import baseEachRight from '../internal/baseEachRight'; +import baseReduce from '../internal/baseReduce'; +import isArray from '../lang/isArray'; + +/** + * This method is like `_.reduce` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @alias foldr + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * var array = [[0, 1], [2, 3], [4, 5]]; + * _.reduceRight(array, function(flattened, other) { return flattened.concat(other); }, []); + * // => [4, 5, 2, 3, 0, 1] + */ +function reduceRight(collection, iteratee, accumulator, thisArg) { + var func = isArray(collection) ? arrayReduceRight : baseReduce; + return func(collection, baseCallback(iteratee, thisArg, 4), accumulator, arguments.length < 3, baseEachRight); +} + +export default reduceRight; diff --git a/collection/reject.js b/collection/reject.js new file mode 100644 index 0000000000..801e46d5d3 --- /dev/null +++ b/collection/reject.js @@ -0,0 +1,52 @@ +import arrayFilter from '../internal/arrayFilter'; +import baseCallback from '../internal/baseCallback'; +import baseFilter from '../internal/baseFilter'; +import isArray from '../lang/isArray'; + +/** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the new filtered array. + * @example + * + * var odds = _.reject([1, 2, 3, 4], function(n) { return n % 2 == 0; }); + * // => [1, 3] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.reject(users, 'active'), 'user'); + * // => ['barney'] + * + * // using the "_.matches" callback shorthand + * _.pluck(_.reject(users, { 'age': 36 }), 'user'); + * // => ['fred'] + */ +function reject(collection, predicate, thisArg) { + var func = isArray(collection) ? arrayFilter : baseFilter; + predicate = baseCallback(predicate, thisArg, 3); + return func(collection, function(value, index, collection) { + return !predicate(value, index, collection); + }); +} + +export default reject; diff --git a/collection/sample.js b/collection/sample.js new file mode 100644 index 0000000000..93ba9bc8dc --- /dev/null +++ b/collection/sample.js @@ -0,0 +1,38 @@ +import baseRandom from '../internal/baseRandom'; +import isIterateeCall from '../internal/isIterateeCall'; +import shuffle from './shuffle'; +import toIterable from '../internal/toIterable'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMin = Math.min; + +/** + * Gets a random element or `n` random elements from a collection. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to sample. + * @param {number} [n] The number of elements to sample. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {*} Returns the random sample(s). + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + * + * _.sample([1, 2, 3, 4], 2); + * // => [3, 1] + */ +function sample(collection, n, guard) { + if (guard ? isIterateeCall(collection, n, guard) : n == null) { + collection = toIterable(collection); + var length = collection.length; + return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; + } + var result = shuffle(collection); + result.length = nativeMin(n < 0 ? 0 : (+n || 0), result.length); + return result; +} + +export default sample; diff --git a/collection/select.js b/collection/select.js new file mode 100644 index 0000000000..ccc6e071fd --- /dev/null +++ b/collection/select.js @@ -0,0 +1,2 @@ +import filter from './filter' +export default filter; diff --git a/collection/shuffle.js b/collection/shuffle.js new file mode 100644 index 0000000000..5739872e52 --- /dev/null +++ b/collection/shuffle.js @@ -0,0 +1,36 @@ +import baseRandom from '../internal/baseRandom'; +import toIterable from '../internal/toIterable'; + +/** + * Creates an array of shuffled values, using a version of the Fisher-Yates + * shuffle. See [Wikipedia](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle) + * for more details. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4]); + * // => [4, 1, 3, 2] + */ +function shuffle(collection) { + collection = toIterable(collection); + + var index = -1, + length = collection.length, + result = Array(length); + + while (++index < length) { + var rand = baseRandom(0, index); + if (index != rand) { + result[index] = result[rand]; + } + result[rand] = collection[index]; + } + return result; +} + +export default shuffle; diff --git a/collection/size.js b/collection/size.js new file mode 100644 index 0000000000..19f9a2656a --- /dev/null +++ b/collection/size.js @@ -0,0 +1,29 @@ +import isLength from '../internal/isLength'; +import keys from '../object/keys'; + +/** + * Gets the size of `collection` by returning `collection.length` for + * array-like values or the number of own enumerable properties for objects. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the size of `collection`. + * @example + * + * _.size([1, 2]); + * // => 2 + * + * _.size({ 'one': 1, 'two': 2, 'three': 3 }); + * // => 3 + * + * _.size('pebbles'); + * // => 7 + */ +function size(collection) { + var length = collection ? collection.length : 0; + return isLength(length) ? length : keys(collection).length; +} + +export default size; diff --git a/collection/some.js b/collection/some.js new file mode 100644 index 0000000000..c3d1a43059 --- /dev/null +++ b/collection/some.js @@ -0,0 +1,56 @@ +import arraySome from '../internal/arraySome'; +import baseCallback from '../internal/baseCallback'; +import baseSome from '../internal/baseSome'; +import isArray from '../lang/isArray'; + +/** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * The function returns as soon as it finds a passing value and does not iterate + * over the entire collection. The predicate is bound to `thisArg` and invoked + * with three arguments; (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @alias any + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * // using the "_.property" callback shorthand + * _.some(users, 'active'); + * // => true + * + * // using the "_.matches" callback shorthand + * _.some(users, { 'age': 1 }); + * // => false + */ +function some(collection, predicate, thisArg) { + var func = isArray(collection) ? arraySome : baseSome; + if (typeof predicate != 'function' || typeof thisArg != 'undefined') { + predicate = baseCallback(predicate, thisArg, 3); + } + return func(collection, predicate); +} + +export default some; diff --git a/collection/sortBy.js b/collection/sortBy.js new file mode 100644 index 0000000000..f9b762bf54 --- /dev/null +++ b/collection/sortBy.js @@ -0,0 +1,64 @@ +import baseCallback from '../internal/baseCallback'; +import baseEach from '../internal/baseEach'; +import baseSortBy from '../internal/baseSortBy'; +import compareAscending from '../internal/compareAscending'; +import isIterateeCall from '../internal/isIterateeCall'; +import isLength from '../internal/isLength'; + +/** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection through `iteratee`. This method performs + * a stable sort, that is, it preserves the original sort order of equal elements. + * The `iteratee` is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array|Function|Object|string} [iteratee=_.identity] The function + * invoked per iteration. If a property name or an object is provided it is + * used to create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new sorted array. + * @example + * + * _.sortBy([1, 2, 3], function(n) { return Math.sin(n); }); + * // => [3, 1, 2] + * + * _.sortBy([1, 2, 3], function(n) { return this.sin(n); }, Math); + * // => [3, 1, 2] + * + * var users = [ + * { 'user': 'fred' }, + * { 'user': 'pebbles' }, + * { 'user': 'barney' } + * ]; + * + * // using the "_.property" callback shorthand + * _.pluck(_.sortBy(users, 'user'), 'user'); + * // => ['barney', 'fred', 'pebbles'] + */ +function sortBy(collection, iteratee, thisArg) { + var index = -1, + length = collection ? collection.length : 0, + result = isLength(length) ? Array(length) : []; + + if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + iteratee = null; + } + iteratee = baseCallback(iteratee, thisArg, 3); + baseEach(collection, function(value, key, collection) { + result[++index] = { 'criteria': iteratee(value, key, collection), 'index': index, 'value': value }; + }); + return baseSortBy(result, compareAscending); +} + +export default sortBy; diff --git a/collection/sortByAll.js b/collection/sortByAll.js new file mode 100644 index 0000000000..e7ea4712a8 --- /dev/null +++ b/collection/sortByAll.js @@ -0,0 +1,53 @@ +import baseEach from '../internal/baseEach'; +import baseFlatten from '../internal/baseFlatten'; +import baseSortBy from '../internal/baseSortBy'; +import compareMultipleAscending from '../internal/compareMultipleAscending'; +import isIterateeCall from '../internal/isIterateeCall'; +import isLength from '../internal/isLength'; + +/** + * This method is like `_.sortBy` except that it sorts by property names + * instead of an iteratee function. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(string|string[])} props The property names to sort by, + * specified as individual property names or arrays of property names. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 26 }, + * { 'user': 'fred', 'age': 30 } + * ]; + * + * _.map(_.sortByAll(users, ['user', 'age']), _.values); + * // => [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] + */ +function sortByAll(collection) { + var args = arguments; + if (args.length > 3 && isIterateeCall(args[1], args[2], args[3])) { + args = [collection, args[1]]; + } + var index = -1, + length = collection ? collection.length : 0, + props = baseFlatten(args, false, false, 1), + result = isLength(length) ? Array(length) : []; + + baseEach(collection, function(value, key, collection) { + var length = props.length, + criteria = Array(length); + + while (length--) { + criteria[length] = value == null ? undefined : value[props[length]]; + } + result[++index] = { 'criteria': criteria, 'index': index, 'value': value }; + }); + return baseSortBy(result, compareMultipleAscending); +} + +export default sortByAll; diff --git a/collection/where.js b/collection/where.js new file mode 100644 index 0000000000..ec7c9bcb12 --- /dev/null +++ b/collection/where.js @@ -0,0 +1,35 @@ +import filter from './filter'; +import matches from '../utility/matches'; + +/** + * Performs a deep comparison between each element in `collection` and the + * source object, returning an array of all elements that have equivalent + * property values. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {Array} Returns the new filtered array. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'status': 'busy', 'pets': ['hoppy'] }, + * { 'user': 'fred', 'age': 40, 'status': 'busy', 'pets': ['baby puss', 'dino'] } + * ]; + * + * _.pluck(_.where(users, { 'age': 36 }), 'user'); + * // => ['barney'] + * + * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); + * // => ['fred'] + * + * _.pluck(_.where(users, { 'status': 'busy' }), 'user'); + * // => ['barney', 'fred'] + */ +function where(collection, source) { + return filter(collection, matches(source)); +} + +export default where; diff --git a/date.js b/date.js new file mode 100644 index 0000000000..9fa88963cc --- /dev/null +++ b/date.js @@ -0,0 +1,5 @@ +import now from './date/now'; + +export default { + 'now': now +}; diff --git a/date/now.js b/date/now.js new file mode 100644 index 0000000000..7be123dbfb --- /dev/null +++ b/date/now.js @@ -0,0 +1,22 @@ +import isNative from '../lang/isNative'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeNow = isNative(nativeNow = Date.now) && nativeNow; + +/** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Date + * @example + * + * _.defer(function(stamp) { console.log(_.now() - stamp); }, _.now()); + * // => logs the number of milliseconds it took for the deferred function to be invoked + */ +var now = nativeNow || function() { + return new Date().getTime(); +}; + +export default now; diff --git a/function.js b/function.js new file mode 100644 index 0000000000..121b2b1051 --- /dev/null +++ b/function.js @@ -0,0 +1,49 @@ +import after from './function/after'; +import ary from './function/ary'; +import backflow from './function/backflow'; +import before from './function/before'; +import bind from './function/bind'; +import bindAll from './function/bindAll'; +import bindKey from './function/bindKey'; +import compose from './function/compose'; +import curry from './function/curry'; +import curryRight from './function/curryRight'; +import debounce from './function/debounce'; +import defer from './function/defer'; +import delay from './function/delay'; +import flow from './function/flow'; +import flowRight from './function/flowRight'; +import memoize from './function/memoize'; +import negate from './function/negate'; +import once from './function/once'; +import partial from './function/partial'; +import partialRight from './function/partialRight'; +import rearg from './function/rearg'; +import throttle from './function/throttle'; +import wrap from './function/wrap'; + +export default { + 'after': after, + 'ary': ary, + 'backflow': backflow, + 'before': before, + 'bind': bind, + 'bindAll': bindAll, + 'bindKey': bindKey, + 'compose': compose, + 'curry': curry, + 'curryRight': curryRight, + 'debounce': debounce, + 'defer': defer, + 'delay': delay, + 'flow': flow, + 'flowRight': flowRight, + 'memoize': memoize, + 'negate': negate, + 'once': once, + 'partial': partial, + 'partialRight': partialRight, + 'rearg': rearg, + 'throttle': throttle, + 'wrap': wrap +}; diff --git a/function/after.js b/function/after.js new file mode 100644 index 0000000000..590c4ffa04 --- /dev/null +++ b/function/after.js @@ -0,0 +1,51 @@ +import isFunction from '../lang/isFunction'; +import root from '../internal/root'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsFinite = root.isFinite; + +/** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it is called `n` or more times. + * + * @static + * @memberOf _ + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => logs 'done saving!' after the two async saves have completed + */ +function after(n, func) { + if (!isFunction(func)) { + if (isFunction(n)) { + var temp = n; + n = func; + func = temp; + } else { + throw new TypeError(FUNC_ERROR_TEXT); + } + } + n = nativeIsFinite(n = +n) ? n : 0; + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; +} + +export default after; diff --git a/function/ary.js b/function/ary.js new file mode 100644 index 0000000000..730d9b2329 --- /dev/null +++ b/function/ary.js @@ -0,0 +1,34 @@ +import createWrapper from '../internal/createWrapper'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** Used to compose bitmasks for wrapper metadata. */ +var ARY_FLAG = 256; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * Creates a function that accepts up to `n` arguments ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to cap arguments for. + * @param {number} [n=func.length] The arity cap. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new function. + * @example + * + * _.map(['6', '8', '10'], _.ary(parseInt, 1)); + * // => [6, 8, 10] + */ +function ary(func, n, guard) { + if (guard && isIterateeCall(func, n, guard)) { + n = null; + } + n = (func && n == null) ? func.length : nativeMax(+n || 0, 0); + return createWrapper(func, ARY_FLAG, null, null, null, null, n); +} + +export default ary; diff --git a/function/backflow.js b/function/backflow.js new file mode 100644 index 0000000000..69295194f1 --- /dev/null +++ b/function/backflow.js @@ -0,0 +1,2 @@ +import flowRight from './flowRight' +export default flowRight; diff --git a/function/before.js b/function/before.js new file mode 100644 index 0000000000..8ddaae6d6d --- /dev/null +++ b/function/before.js @@ -0,0 +1,43 @@ +import isFunction from '../lang/isFunction'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it is called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery('#add').on('click', _.before(5, addContactToList)); + * // => allows adding up to 4 contacts to the list + */ +function before(n, func) { + var result; + if (!isFunction(func)) { + if (isFunction(n)) { + var temp = n; + n = func; + func = temp; + } else { + throw new TypeError(FUNC_ERROR_TEXT); + } + } + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } else { + func = null; + } + return result; + }; +} + +export default before; diff --git a/function/bind.js b/function/bind.js new file mode 100644 index 0000000000..88d1359106 --- /dev/null +++ b/function/bind.js @@ -0,0 +1,58 @@ +import baseSlice from '../internal/baseSlice'; +import createWrapper from '../internal/createWrapper'; +import replaceHolders from '../internal/replaceHolders'; + +/** Used to compose bitmasks for wrapper metadata. */ +var BIND_FLAG = 1, + PARTIAL_FLAG = 32; + +/** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and prepends any additional `_.bind` arguments to those provided to the + * bound function. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind` this method does not set the `length` + * property of bound functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [args] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var greet = function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * }; + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // using placeholders + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ +function bind(func, thisArg) { + var bitmask = BIND_FLAG; + if (arguments.length > 2) { + var partials = baseSlice(arguments, 2), + holders = replaceHolders(partials, bind.placeholder); + + bitmask |= PARTIAL_FLAG; + } + return createWrapper(func, bitmask, thisArg, partials, holders); +} + +// Assign default placeholders. +bind.placeholder = {}; + +export default bind; diff --git a/function/bindAll.js b/function/bindAll.js new file mode 100644 index 0000000000..6d68932110 --- /dev/null +++ b/function/bindAll.js @@ -0,0 +1,39 @@ +import baseBindAll from '../internal/baseBindAll'; +import baseFlatten from '../internal/baseFlatten'; +import functions from '../object/functions'; + +/** + * Binds methods of an object to the object itself, overwriting the existing + * method. Method names may be specified as individual arguments or as arrays + * of method names. If no method names are provided all enumerable function + * properties, own and inherited, of `object` are bound. + * + * **Note:** This method does not set the `length` property of bound functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Object} object The object to bind and assign the bound methods to. + * @param {...(string|string[])} [methodNames] The object method names to bind, + * specified as individual method names or arrays of method names. + * @returns {Object} Returns `object`. + * @example + * + * var view = { + * 'label': 'docs', + * 'onClick': function() { console.log('clicked ' + this.label); } + * }; + * + * _.bindAll(view); + * jQuery('#docs').on('click', view.onClick); + * // => logs 'clicked docs' when the element is clicked + */ +function bindAll(object) { + return baseBindAll(object, + arguments.length > 1 + ? baseFlatten(arguments, false, false, 1) + : functions(object) + ); +} + +export default bindAll; diff --git a/function/bindKey.js b/function/bindKey.js new file mode 100644 index 0000000000..12e07ac729 --- /dev/null +++ b/function/bindKey.js @@ -0,0 +1,68 @@ +import baseSlice from '../internal/baseSlice'; +import createWrapper from '../internal/createWrapper'; +import replaceHolders from '../internal/replaceHolders'; + +/** Used to compose bitmasks for wrapper metadata. */ +var BIND_FLAG = 1, + BIND_KEY_FLAG = 2, + PARTIAL_FLAG = 32; + +/** + * Creates a function that invokes the method at `object[key]` and prepends + * any additional `_.bindKey` arguments to those provided to the bound function. + * + * This method differs from `_.bind` by allowing bound functions to reference + * methods that may be redefined or don't yet exist. + * See [Peter Michaux's article](http://michaux.ca/articles/lazy-function-definition-pattern) + * for more details. + * + * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * @static + * @memberOf _ + * @category Function + * @param {Object} object The object the method belongs to. + * @param {string} key The key of the method. + * @param {...*} [args] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'user': 'fred', + * 'greet': function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * }; + * + * var bound = _.bindKey(object, 'greet', 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * object.greet = function(greeting, punctuation) { + * return greeting + 'ya ' + this.user + punctuation; + * }; + * + * bound('!'); + * // => 'hiya fred!' + * + * // using placeholders + * var bound = _.bindKey(object, 'greet', _, '!'); + * bound('hi'); + * // => 'hiya fred!' + */ +function bindKey(object, key) { + var bitmask = BIND_FLAG | BIND_KEY_FLAG; + if (arguments.length > 2) { + var partials = baseSlice(arguments, 2), + holders = replaceHolders(partials, bindKey.placeholder); + + bitmask |= PARTIAL_FLAG; + } + return createWrapper(key, bitmask, object, partials, holders); +} + +// Assign default placeholders. +bindKey.placeholder = {}; + +export default bindKey; diff --git a/function/compose.js b/function/compose.js new file mode 100644 index 0000000000..69295194f1 --- /dev/null +++ b/function/compose.js @@ -0,0 +1,2 @@ +import flowRight from './flowRight' +export default flowRight; diff --git a/function/curry.js b/function/curry.js new file mode 100644 index 0000000000..e63b281b3b --- /dev/null +++ b/function/curry.js @@ -0,0 +1,59 @@ +import createWrapper from '../internal/createWrapper'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** Used to compose bitmasks for wrapper metadata. */ +var CURRY_FLAG = 8; + +/** + * Creates a function that accepts one or more arguments of `func` that when + * called either invokes `func` returning its result, if all `func` arguments + * have been provided, or returns a function that accepts one or more of the + * remaining `func` arguments, and so on. The arity of `func` may be specified + * if `func.length` is not sufficient. + * + * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for provided arguments. + * + * **Note:** This method does not set the `length` property of curried functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curry(abc); + * + * curried(1)(2)(3); + * // => [1, 2, 3] + * + * curried(1, 2)(3); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // using placeholders + * curried(1)(_, 3)(2); + * // => [1, 2, 3] + */ +function curry(func, arity, guard) { + if (guard && isIterateeCall(func, arity, guard)) { + arity = null; + } + var result = createWrapper(func, CURRY_FLAG, null, null, null, null, null, arity); + result.placeholder = curry.placeholder; + return result; +} + +// Assign default placeholders. +curry.placeholder = {}; + +export default curry; diff --git a/function/curryRight.js b/function/curryRight.js new file mode 100644 index 0000000000..4f9ff35bf8 --- /dev/null +++ b/function/curryRight.js @@ -0,0 +1,56 @@ +import createWrapper from '../internal/createWrapper'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** Used to compose bitmasks for wrapper metadata. */ +var CURRY_RIGHT_FLAG = 16; + +/** + * This method is like `_.curry` except that arguments are applied to `func` + * in the manner of `_.partialRight` instead of `_.partial`. + * + * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for provided arguments. + * + * **Note:** This method does not set the `length` property of curried functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curryRight(abc); + * + * curried(3)(2)(1); + * // => [1, 2, 3] + * + * curried(2, 3)(1); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // using placeholders + * curried(3)(1, _)(2); + * // => [1, 2, 3] + */ +function curryRight(func, arity, guard) { + if (guard && isIterateeCall(func, arity, guard)) { + arity = null; + } + var result = createWrapper(func, CURRY_RIGHT_FLAG, null, null, null, null, null, arity); + result.placeholder = curryRight.placeholder; + return result; +} + +// Assign default placeholders. +curryRight.placeholder = {}; + +export default curryRight; diff --git a/function/debounce.js b/function/debounce.js new file mode 100644 index 0000000000..c54cdd784b --- /dev/null +++ b/function/debounce.js @@ -0,0 +1,187 @@ +import isFunction from '../lang/isFunction'; +import isObject from '../lang/isObject'; +import now from '../date/now'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * Creates a function that delays invoking `func` until after `wait` milliseconds + * have elapsed since the last time it was invoked. The created function comes + * with a `cancel` method to cancel delayed invocations. Provide an options + * object to indicate that `func` should be invoked on the leading and/or + * trailing edge of the `wait` timeout. Subsequent calls to the debounced + * function return the result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the debounced function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to debounce. + * @param {number} wait The number of milliseconds to delay. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=false] Specify invoking on the leading + * edge of the timeout. + * @param {number} [options.maxWait] The maximum time `func` is allowed to be + * delayed before it is invoked. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // avoid costly calculations while the window size is in flux + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // invoke `sendMail` when the click event is fired, debouncing subsequent calls + * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // ensure `batchLog` is invoked once after 1 second of debounced calls + * var source = new EventSource('/stream'); + * jQuery(source).on('message', _.debounce(batchLog, 250, { + * 'maxWait': 1000 + * })); + * + * // cancel a debounced call + * var todoChanges = _.debounce(batchLog, 1000); + * Object.observe(models.todo, todoChanges); + * + * Object.observe(models, function(changes) { + * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { + * todoChanges.cancel(); + * } + * }, ['delete']); + * + * // ...at some point `models.todo` is changed + * models.todo.completed = true; + * + * // ...before 1 second has passed `models.todo` is deleted + * // which cancels the debounced `todoChanges` call + * delete models.todo; + */ +function debounce(func, wait, options) { + var args, + maxTimeoutId, + result, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; + + if (!isFunction(func)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = wait < 0 ? 0 : wait; + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { + leading = options.leading; + maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); + trailing = 'trailing' in options ? options.trailing : trailing; + } + + function cancel() { + if (timeoutId) { + clearTimeout(timeoutId); + } + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + } + + function delayed() { + var remaining = wait - (now() - stamp); + if (remaining <= 0 || remaining > wait) { + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + var isCalled = trailingCall; + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } + } else { + timeoutId = setTimeout(delayed, remaining); + } + } + + function maxDelayed() { + if (timeoutId) { + clearTimeout(timeoutId); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (trailing || (maxWait !== wait)) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } + } + + function debounced() { + args = arguments; + stamp = now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); + + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0 || remaining > maxWait; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + return result; + } + debounced.cancel = cancel; + return debounced; +} + +export default debounce; diff --git a/function/defer.js b/function/defer.js new file mode 100644 index 0000000000..1e102a9eba --- /dev/null +++ b/function/defer.js @@ -0,0 +1,22 @@ +import baseDelay from '../internal/baseDelay'; + +/** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { console.log(text); }, 'deferred'); + * // logs 'deferred' after one or more milliseconds + */ +function defer(func) { + return baseDelay(func, 1, arguments, 1); +} + +export default defer; diff --git a/function/delay.js b/function/delay.js new file mode 100644 index 0000000000..86055973d9 --- /dev/null +++ b/function/delay.js @@ -0,0 +1,23 @@ +import baseDelay from '../internal/baseDelay'; + +/** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke the function with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { console.log(text); }, 1000, 'later'); + * // => logs 'later' after one second + */ +function delay(func, wait) { + return baseDelay(func, wait, arguments, 2); +} + +export default delay; diff --git a/function/flow.js b/function/flow.js new file mode 100644 index 0000000000..25b8b2bf9c --- /dev/null +++ b/function/flow.js @@ -0,0 +1,52 @@ +import arrayEvery from '../internal/arrayEvery'; +import isFunction from '../lang/isFunction'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * Creates a function that returns the result of invoking the provided + * functions with the `this` binding of the created function, where each + * successive invocation is supplied the return value of the previous. + * + * @static + * @memberOf _ + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function add(x, y) { + * return x + y; + * } + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flow(add, square); + * addSquare(1, 2); + * // => 9 + */ +function flow() { + var funcs = arguments, + length = funcs.length; + + if (!length) { + return function() {}; + } + if (!arrayEvery(funcs, isFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var index = 0, + result = funcs[index].apply(this, arguments); + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; +} + +export default flow; diff --git a/function/flowRight.js b/function/flowRight.js new file mode 100644 index 0000000000..6914c198e4 --- /dev/null +++ b/function/flowRight.js @@ -0,0 +1,52 @@ +import arrayEvery from '../internal/arrayEvery'; +import isFunction from '../lang/isFunction'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * This method is like `_.flow` except that it creates a function that + * invokes the provided functions from right to left. + * + * @static + * @memberOf _ + * @alias backflow, compose + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function add(x, y) { + * return x + y; + * } + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flowRight(square, add); + * addSquare(1, 2); + * // => 9 + */ +function flowRight() { + var funcs = arguments, + fromIndex = funcs.length - 1; + + if (fromIndex < 0) { + return function() {}; + } + if (!arrayEvery(funcs, isFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var index = fromIndex, + result = funcs[index].apply(this, arguments); + + while (index--) { + result = funcs[index].call(this, result); + } + return result; + }; +} + +export default flowRight; diff --git a/function/memoize.js b/function/memoize.js new file mode 100644 index 0000000000..cd66cf73e6 --- /dev/null +++ b/function/memoize.js @@ -0,0 +1,82 @@ +import MapCache from '../internal/MapCache'; +import isFunction from '../lang/isFunction'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is coerced to a string and used as the + * cache key. The `func` is invoked with the `this` binding of the memoized + * function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the ES `Map` method interface + * of `get`, `has`, and `set`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object) + * for more details. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoizing function. + * @example + * + * var upperCase = _.memoize(function(string) { + * return string.toUpperCase(); + * }); + * + * upperCase('fred'); + * // => 'FRED' + * + * // modifying the result cache + * upperCase.cache.set('fred, 'BARNEY'); + * upperCase('fred'); + * // => 'BARNEY' + * + * // replacing `_.memoize.Cache` + * var object = { 'user': 'fred' }; + * var other = { 'user': 'barney' }; + * var identity = _.memoize(_.identity); + * + * identity(object); + * // => { 'user': 'fred' } + * identity(other); + * // => { 'user': 'fred' } + * + * _.memoize.Cache = WeakMap; + * var identity = _.memoize(_.identity); + * + * identity(object); + * // => { 'user': 'fred' } + * identity(other); + * // => { 'user': 'barney' } + */ +function memoize(func, resolver) { + if (!isFunction(func) || (resolver && !isFunction(resolver))) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var cache = memoized.cache, + key = resolver ? resolver.apply(this, arguments) : arguments[0]; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, arguments); + cache.set(key, result); + return result; + }; + memoized.cache = new memoize.Cache; + return memoized; +} + +// Assign cache to `_.memoize`. +memoize.Cache = MapCache; + +export default memoize; diff --git a/function/negate.js b/function/negate.js new file mode 100644 index 0000000000..1222b2466b --- /dev/null +++ b/function/negate.js @@ -0,0 +1,34 @@ +import isFunction from '../lang/isFunction'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ +function negate(predicate) { + if (!isFunction(predicate)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + return !predicate.apply(this, arguments); + }; +} + +export default negate; diff --git a/function/once.js b/function/once.js new file mode 100644 index 0000000000..a6e3aca72e --- /dev/null +++ b/function/once.js @@ -0,0 +1,25 @@ +import before from './before'; + +/** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first call. The `func` is invoked + * with the `this` binding of the created function. + * + * @static + * @memberOf _ + * @type Function + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // `initialize` invokes `createApplication` once + */ +function once(func) { + return before(func, 2); +} + +export default once; diff --git a/function/partial.js b/function/partial.js new file mode 100644 index 0000000000..9b8291dbb8 --- /dev/null +++ b/function/partial.js @@ -0,0 +1,50 @@ +import baseSlice from '../internal/baseSlice'; +import createWrapper from '../internal/createWrapper'; +import replaceHolders from '../internal/replaceHolders'; + +/** Used to compose bitmasks for wrapper metadata. */ +var PARTIAL_FLAG = 32; + +/** + * Creates a function that invokes `func` with `partial` arguments prepended + * to those provided to the new function. This method is like `_.bind` except + * it does **not** alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method does not set the `length` property of partially + * applied functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [args] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var greet = function(greeting, name) { + * return greeting + ' ' + name; + * }; + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // using placeholders + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ +function partial(func) { + var partials = baseSlice(arguments, 1), + holders = replaceHolders(partials, partial.placeholder); + + return createWrapper(func, PARTIAL_FLAG, null, partials, holders); +} + +// Assign default placeholders. +partial.placeholder = {}; + +export default partial; diff --git a/function/partialRight.js b/function/partialRight.js new file mode 100644 index 0000000000..3bb858a43e --- /dev/null +++ b/function/partialRight.js @@ -0,0 +1,49 @@ +import baseSlice from '../internal/baseSlice'; +import createWrapper from '../internal/createWrapper'; +import replaceHolders from '../internal/replaceHolders'; + +/** Used to compose bitmasks for wrapper metadata. */ +var PARTIAL_RIGHT_FLAG = 64; + +/** + * This method is like `_.partial` except that partially applied arguments + * are appended to those provided to the new function. + * + * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method does not set the `length` property of partially + * applied functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [args] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * var greet = function(greeting, name) { + * return greeting + ' ' + name; + * }; + * + * var greetFred = _.partialRight(greet, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + * + * // using placeholders + * var sayHelloTo = _.partialRight(greet, 'hello', _); + * sayHelloTo('fred'); + * // => 'hello fred' + */ +function partialRight(func) { + var partials = baseSlice(arguments, 1), + holders = replaceHolders(partials, partialRight.placeholder); + + return createWrapper(func, PARTIAL_RIGHT_FLAG, null, partials, holders); +} + +// Assign default placeholders. +partialRight.placeholder = {}; + +export default partialRight; diff --git a/function/rearg.js b/function/rearg.js new file mode 100644 index 0000000000..6eb2c96f31 --- /dev/null +++ b/function/rearg.js @@ -0,0 +1,38 @@ +import baseFlatten from '../internal/baseFlatten'; +import createWrapper from '../internal/createWrapper'; + +/** Used to compose bitmasks for wrapper metadata. */ +var REARG_FLAG = 128; + +/** + * Creates a function that invokes `func` with arguments arranged according + * to the specified indexes where the argument value at the first index is + * provided as the first argument, the argument value at the second index is + * provided as the second argument, and so on. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to rearrange arguments for. + * @param {...(number|number[])} indexes The arranged argument indexes, + * specified as individual indexes or arrays of indexes. + * @returns {Function} Returns the new function. + * @example + * + * var rearged = _.rearg(function(a, b, c) { + * return [a, b, c]; + * }, 2, 0, 1); + * + * rearged('b', 'c', 'a') + * // => ['a', 'b', 'c'] + * + * var map = _.rearg(_.map, [1, 0]); + * map(function(n) { return n * 3; }, [1, 2, 3]); + * // => [3, 6, 9] + */ +function rearg(func) { + var indexes = baseFlatten(arguments, false, false, 1); + return createWrapper(func, REARG_FLAG, null, null, null, indexes); +} + +export default rearg; diff --git a/function/throttle.js b/function/throttle.js new file mode 100644 index 0000000000..ae001a6825 --- /dev/null +++ b/function/throttle.js @@ -0,0 +1,72 @@ +import debounce from './debounce'; +import isFunction from '../lang/isFunction'; +import isObject from '../lang/isObject'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** Used as an internal `_.debounce` options object by `_.throttle`. */ +var debounceOptions = { + 'leading': false, + 'maxWait': 0, + 'trailing': false +}; + +/** + * Creates a function that only invokes `func` at most once per every `wait` + * milliseconds. The created function comes with a `cancel` method to cancel + * delayed invocations. Provide an options object to indicate that `func` + * should be invoked on the leading and/or trailing edge of the `wait` timeout. + * Subsequent calls to the throttled function return the result of the last + * `func` call. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the throttled function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to throttle. + * @param {number} wait The number of milliseconds to throttle invocations to. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=true] Specify invoking on the leading + * edge of the timeout. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // avoid excessively updating the position while scrolling + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }) + * jQuery('.interactive').on('click', throttled); + * + * // cancel a trailing throttled call + * jQuery(window).on('popstate', throttled.cancel); + */ +function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (!isFunction(func)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (options === false) { + leading = false; + } else if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + debounceOptions.leading = leading; + debounceOptions.maxWait = +wait; + debounceOptions.trailing = trailing; + return debounce(func, wait, debounceOptions); +} + +export default throttle; diff --git a/function/wrap.js b/function/wrap.js new file mode 100644 index 0000000000..35f4906051 --- /dev/null +++ b/function/wrap.js @@ -0,0 +1,33 @@ +import createWrapper from '../internal/createWrapper'; +import identity from '../utility/identity'; + +/** Used to compose bitmasks for wrapper metadata. */ +var PARTIAL_FLAG = 32; + +/** + * Creates a function that provides `value` to the wrapper function as its + * first argument. Any additional arguments provided to the function are + * appended to those provided to the wrapper function. The wrapper is invoked + * with the `this` binding of the created function. + * + * @static + * @memberOf _ + * @category Function + * @param {*} value The value to wrap. + * @param {Function} wrapper The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

' + func(text) + '

'; + * }); + * + * p('fred, barney, & pebbles'); + * // => '

fred, barney, & pebbles

' + */ +function wrap(value, wrapper) { + wrapper = wrapper == null ? identity : wrapper; + return createWrapper(wrapper, PARTIAL_FLAG, null, [value], []); +} + +export default wrap; diff --git a/internal/LazyWrapper.js b/internal/LazyWrapper.js new file mode 100644 index 0000000000..5c463ee3a4 --- /dev/null +++ b/internal/LazyWrapper.js @@ -0,0 +1,21 @@ +/** Used as references for `-Infinity` and `Infinity`. */ +var POSITIVE_INFINITY = Number.POSITIVE_INFINITY; + +/** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @param {*} value The value to wrap. + */ +function LazyWrapper(value) { + this.actions = null; + this.dir = 1; + this.dropCount = 0; + this.filtered = false; + this.iteratees = null; + this.takeCount = POSITIVE_INFINITY; + this.views = null; + this.wrapped = value; +} + +export default LazyWrapper; diff --git a/internal/LodashWrapper.js b/internal/LodashWrapper.js new file mode 100644 index 0000000000..95a1e3675c --- /dev/null +++ b/internal/LodashWrapper.js @@ -0,0 +1,15 @@ +/** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable chaining for all wrapper methods. + * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value. + */ +function LodashWrapper(value, chainAll, actions) { + this.__actions__ = actions || []; + this.__chain__ = !!chainAll; + this.__wrapped__ = value; +} + +export default LodashWrapper; diff --git a/internal/MapCache.js b/internal/MapCache.js new file mode 100644 index 0000000000..d4a55adf90 --- /dev/null +++ b/internal/MapCache.js @@ -0,0 +1,24 @@ +import mapDelete from './mapDelete'; +import mapGet from './mapGet'; +import mapHas from './mapHas'; +import mapSet from './mapSet'; + +/** + * Creates a cache object to store key/value pairs. + * + * @private + * @static + * @name Cache + * @memberOf _.memoize + */ +function MapCache() { + this.__data__ = {}; +} + +// Add functions to the `Map` cache. +MapCache.prototype['delete'] = mapDelete; +MapCache.prototype.get = mapGet; +MapCache.prototype.has = mapHas; +MapCache.prototype.set = mapSet; + +export default MapCache; diff --git a/internal/SetCache.js b/internal/SetCache.js new file mode 100644 index 0000000000..b43e828ea7 --- /dev/null +++ b/internal/SetCache.js @@ -0,0 +1,30 @@ +import cachePush from './cachePush'; +import isNative from '../lang/isNative'; +import root from './root'; + +/** Native method references. */ +var Set = isNative(Set = root.Set) && Set; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate; + +/** + * + * Creates a cache object to store unique values. + * + * @private + * @param {Array} [values] The values to cache. + */ +function SetCache(values) { + var length = values ? values.length : 0; + + this.data = { 'hash': nativeCreate(null), 'set': new Set }; + while (length--) { + this.push(values[length]); + } +} + +// Add functions to the `Set` cache. +SetCache.prototype.push = cachePush; + +export default SetCache; diff --git a/internal/arrayCopy.js b/internal/arrayCopy.js new file mode 100644 index 0000000000..0b34ccb988 --- /dev/null +++ b/internal/arrayCopy.js @@ -0,0 +1,20 @@ +/** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ +function arrayCopy(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; +} + +export default arrayCopy; diff --git a/internal/arrayEach.js b/internal/arrayEach.js new file mode 100644 index 0000000000..bb463580ae --- /dev/null +++ b/internal/arrayEach.js @@ -0,0 +1,22 @@ +/** + * A specialized version of `_.forEach` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ +function arrayEach(array, iteratee) { + var index = -1, + length = array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; +} + +export default arrayEach; diff --git a/internal/arrayEachRight.js b/internal/arrayEachRight.js new file mode 100644 index 0000000000..61c51d537e --- /dev/null +++ b/internal/arrayEachRight.js @@ -0,0 +1,21 @@ +/** + * A specialized version of `_.forEachRight` for arrays without support for + * callback shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ +function arrayEachRight(array, iteratee) { + var length = array.length; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; +} + +export default arrayEachRight; diff --git a/internal/arrayEvery.js b/internal/arrayEvery.js new file mode 100644 index 0000000000..1eaf11275d --- /dev/null +++ b/internal/arrayEvery.js @@ -0,0 +1,23 @@ +/** + * A specialized version of `_.every` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ +function arrayEvery(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; +} + +export default arrayEvery; diff --git a/internal/arrayFilter.js b/internal/arrayFilter.js new file mode 100644 index 0000000000..e3d86f0b2d --- /dev/null +++ b/internal/arrayFilter.js @@ -0,0 +1,25 @@ +/** + * A specialized version of `_.filter` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ +function arrayFilter(array, predicate) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[++resIndex] = value; + } + } + return result; +} + +export default arrayFilter; diff --git a/internal/arrayMap.js b/internal/arrayMap.js new file mode 100644 index 0000000000..95a9bd3e6f --- /dev/null +++ b/internal/arrayMap.js @@ -0,0 +1,21 @@ +/** + * A specialized version of `_.map` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ +function arrayMap(array, iteratee) { + var index = -1, + length = array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; +} + +export default arrayMap; diff --git a/internal/arrayMax.js b/internal/arrayMax.js new file mode 100644 index 0000000000..2d73385538 --- /dev/null +++ b/internal/arrayMax.js @@ -0,0 +1,25 @@ +/** Used as references for `-Infinity` and `Infinity`. */ +var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY; + +/** + * A specialized version of `_.max` for arrays without support for iteratees. + * + * @private + * @param {Array} array The array to iterate over. + * @returns {*} Returns the maximum value. + */ +function arrayMax(array) { + var index = -1, + length = array.length, + result = NEGATIVE_INFINITY; + + while (++index < length) { + var value = array[index]; + if (value > result) { + result = value; + } + } + return result; +} + +export default arrayMax; diff --git a/internal/arrayMin.js b/internal/arrayMin.js new file mode 100644 index 0000000000..0bc05de093 --- /dev/null +++ b/internal/arrayMin.js @@ -0,0 +1,25 @@ +/** Used as references for `-Infinity` and `Infinity`. */ +var POSITIVE_INFINITY = Number.POSITIVE_INFINITY; + +/** + * A specialized version of `_.min` for arrays without support for iteratees. + * + * @private + * @param {Array} array The array to iterate over. + * @returns {*} Returns the minimum value. + */ +function arrayMin(array) { + var index = -1, + length = array.length, + result = POSITIVE_INFINITY; + + while (++index < length) { + var value = array[index]; + if (value < result) { + result = value; + } + } + return result; +} + +export default arrayMin; diff --git a/internal/arrayReduce.js b/internal/arrayReduce.js new file mode 100644 index 0000000000..71f33b912a --- /dev/null +++ b/internal/arrayReduce.js @@ -0,0 +1,26 @@ +/** + * A specialized version of `_.reduce` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the first element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ +function arrayReduce(array, iteratee, accumulator, initFromArray) { + var index = -1, + length = array.length; + + if (initFromArray && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; +} + +export default arrayReduce; diff --git a/internal/arrayReduceRight.js b/internal/arrayReduceRight.js new file mode 100644 index 0000000000..cbf35e71f3 --- /dev/null +++ b/internal/arrayReduceRight.js @@ -0,0 +1,24 @@ +/** + * A specialized version of `_.reduceRight` for arrays without support for + * callback shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the last element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ +function arrayReduceRight(array, iteratee, accumulator, initFromArray) { + var length = array.length; + if (initFromArray && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; +} + +export default arrayReduceRight; diff --git a/internal/arraySome.js b/internal/arraySome.js new file mode 100644 index 0000000000..a6a7daaaef --- /dev/null +++ b/internal/arraySome.js @@ -0,0 +1,23 @@ +/** + * A specialized version of `_.some` for arrays without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ +function arraySome(array, predicate) { + var index = -1, + length = array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; +} + +export default arraySome; diff --git a/internal/assignDefaults.js b/internal/assignDefaults.js new file mode 100644 index 0000000000..6f37a2b578 --- /dev/null +++ b/internal/assignDefaults.js @@ -0,0 +1,13 @@ +/** + * Used by `_.defaults` to customize its `_.assign` use. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @returns {*} Returns the value to assign to the destination object. + */ +function assignDefaults(objectValue, sourceValue) { + return typeof objectValue == 'undefined' ? sourceValue : objectValue; +} + +export default assignDefaults; diff --git a/internal/assignOwnDefaults.js b/internal/assignOwnDefaults.js new file mode 100644 index 0000000000..8111ed1ef2 --- /dev/null +++ b/internal/assignOwnDefaults.js @@ -0,0 +1,26 @@ +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used by `_.template` to customize its `_.assign` use. + * + * **Note:** This method is like `assignDefaults` except that it ignores + * inherited property values when checking if a property is `undefined`. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @param {string} key The key associated with the object and source values. + * @param {Object} object The destination object. + * @returns {*} Returns the value to assign to the destination object. + */ +function assignOwnDefaults(objectValue, sourceValue, key, object) { + return (typeof objectValue == 'undefined' || !hasOwnProperty.call(object, key)) + ? sourceValue + : objectValue; +} + +export default assignOwnDefaults; diff --git a/internal/baseAssign.js b/internal/baseAssign.js new file mode 100644 index 0000000000..c64e89e4bd --- /dev/null +++ b/internal/baseAssign.js @@ -0,0 +1,35 @@ +import baseCopy from './baseCopy'; +import keys from '../object/keys'; + +/** + * The base implementation of `_.assign` without support for argument juggling, + * multiple sources, and `this` binding `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} [customizer] The function to customize assigning values. + * @returns {Object} Returns the destination object. + */ +function baseAssign(object, source, customizer) { + var props = keys(source); + if (!customizer) { + return baseCopy(source, object, props); + } + var index = -1, + length = props.length + + while (++index < length) { + var key = props[index], + value = object[key], + result = customizer(value, source[key], key, object, source); + + if ((result === result ? result !== value : value === value) || + (typeof value == 'undefined' && !(key in object))) { + object[key] = result; + } + } + return object; +} + +export default baseAssign; diff --git a/internal/baseAt.js b/internal/baseAt.js new file mode 100644 index 0000000000..99700cdd8c --- /dev/null +++ b/internal/baseAt.js @@ -0,0 +1,32 @@ +import isIndex from './isIndex'; +import isLength from './isLength'; + +/** + * The base implementation of `_.at` without support for strings and individual + * key arguments. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {number[]|string[]} [props] The property names or indexes of elements to pick. + * @returns {Array} Returns the new array of picked elements. + */ +function baseAt(collection, props) { + var index = -1, + length = collection.length, + isArr = isLength(length), + propsLength = props.length, + result = Array(propsLength); + + while(++index < propsLength) { + var key = props[index]; + if (isArr) { + key = parseFloat(key); + result[index] = isIndex(key, length) ? collection[key] : undefined; + } else { + result[index] = collection[key]; + } + } + return result; +} + +export default baseAt; diff --git a/internal/baseBindAll.js b/internal/baseBindAll.js new file mode 100644 index 0000000000..70ffff845c --- /dev/null +++ b/internal/baseBindAll.js @@ -0,0 +1,26 @@ +import createWrapper from './createWrapper'; + +/** Used to compose bitmasks for wrapper metadata. */ +var BIND_FLAG = 1; + +/** + * The base implementation of `_.bindAll` without support for individual + * method name arguments. + * + * @private + * @param {Object} object The object to bind and assign the bound methods to. + * @param {string[]} methodNames The object method names to bind. + * @returns {Object} Returns `object`. + */ +function baseBindAll(object, methodNames) { + var index = -1, + length = methodNames.length; + + while (++index < length) { + var key = methodNames[index]; + object[key] = createWrapper(object[key], BIND_FLAG, object); + } + return object; +} + +export default baseBindAll; diff --git a/internal/baseCallback.js b/internal/baseCallback.js new file mode 100644 index 0000000000..6913af30db --- /dev/null +++ b/internal/baseCallback.js @@ -0,0 +1,34 @@ +import baseMatches from './baseMatches'; +import baseProperty from './baseProperty'; +import baseToString from './baseToString'; +import bindCallback from './bindCallback'; +import identity from '../utility/identity'; +import isBindable from './isBindable'; + +/** + * The base implementation of `_.callback` which supports specifying the + * number of arguments to provide to `func`. + * + * @private + * @param {*} [func=_.identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ +function baseCallback(func, thisArg, argCount) { + var type = typeof func; + if (type == 'function') { + return (typeof thisArg != 'undefined' && isBindable(func)) + ? bindCallback(func, thisArg, argCount) + : func; + } + if (func == null) { + return identity; + } + // Handle "_.property" and "_.matches" style callback shorthands. + return type == 'object' + ? baseMatches(func, !argCount) + : baseProperty(argCount ? baseToString(func) : func); +} + +export default baseCallback; diff --git a/internal/baseClone.js b/internal/baseClone.js new file mode 100644 index 0000000000..e01816f68e --- /dev/null +++ b/internal/baseClone.js @@ -0,0 +1,130 @@ +import arrayCopy from './arrayCopy'; +import arrayEach from './arrayEach'; +import baseCopy from './baseCopy'; +import baseForOwn from './baseForOwn'; +import initCloneArray from './initCloneArray'; +import initCloneByTag from './initCloneByTag'; +import initCloneObject from './initCloneObject'; +import isArray from '../lang/isArray'; +import isObject from '../lang/isObject'; +import keys from '../object/keys'; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** Used to identify `toStringTag` values supported by `_.clone`. */ +var cloneableTags = {}; +cloneableTags[argsTag] = cloneableTags[arrayTag] = +cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = +cloneableTags[dateTag] = cloneableTags[float32Tag] = +cloneableTags[float64Tag] = cloneableTags[int8Tag] = +cloneableTags[int16Tag] = cloneableTags[int32Tag] = +cloneableTags[numberTag] = cloneableTags[objectTag] = +cloneableTags[regexpTag] = cloneableTags[stringTag] = +cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = +cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; +cloneableTags[errorTag] = cloneableTags[funcTag] = +cloneableTags[mapTag] = cloneableTags[setTag] = +cloneableTags[weakMapTag] = false; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * The base implementation of `_.clone` without support for argument juggling + * and `this` binding `customizer` functions. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The object `value` belongs to. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates clones with source counterparts. + * @returns {*} Returns the cloned value. + */ +function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { + var result; + if (customizer) { + result = object ? customizer(value, key, object) : customizer(value); + } + if (typeof result != 'undefined') { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return arrayCopy(value, result); + } + } else { + var tag = objToString.call(value), + isFunc = tag == funcTag; + + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = initCloneObject(isFunc ? {} : value); + if (!isDeep) { + return baseCopy(value, result, keys(value)); + } + } else { + return cloneableTags[tag] + ? initCloneByTag(value, tag, isDeep) + : (object ? value : {}); + } + } + // Check for circular references and return corresponding clone. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == value) { + return stackB[length]; + } + } + // Add the source value to the stack of traversed objects and associate it with its clone. + stackA.push(value); + stackB.push(result); + + // Recursively populate clone (susceptible to call stack limits). + (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { + result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); + }); + return result; +} + +export default baseClone; diff --git a/internal/baseCompareAscending.js b/internal/baseCompareAscending.js new file mode 100644 index 0000000000..b2f85d38ba --- /dev/null +++ b/internal/baseCompareAscending.js @@ -0,0 +1,25 @@ +/** + * The base implementation of `compareAscending` which compares values and + * sorts them in ascending order without guaranteeing a stable sort. + * + * @private + * @param {*} value The value to compare to `other`. + * @param {*} other The value to compare to `value`. + * @returns {number} Returns the sort order indicator for `value`. + */ +function baseCompareAscending(value, other) { + if (value !== other) { + var valIsReflexive = value === value, + othIsReflexive = other === other; + + if (value > other || !valIsReflexive || (typeof value == 'undefined' && othIsReflexive)) { + return 1; + } + if (value < other || !othIsReflexive || (typeof other == 'undefined' && valIsReflexive)) { + return -1; + } + } + return 0; +} + +export default baseCompareAscending; diff --git a/internal/baseCopy.js b/internal/baseCopy.js new file mode 100644 index 0000000000..8c0dbb54c1 --- /dev/null +++ b/internal/baseCopy.js @@ -0,0 +1,25 @@ +/** + * Copies the properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Object} [object={}] The object to copy properties to. + * @param {Array} props The property names to copy. + * @returns {Object} Returns `object`. + */ +function baseCopy(source, object, props) { + if (!props) { + props = object; + object = {}; + } + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + object[key] = source[key]; + } + return object; +} + +export default baseCopy; diff --git a/internal/baseCreate.js b/internal/baseCreate.js new file mode 100644 index 0000000000..ad1c0c0933 --- /dev/null +++ b/internal/baseCreate.js @@ -0,0 +1,24 @@ +import isObject from '../lang/isObject'; +import root from './root'; + +/** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ +var baseCreate = (function() { + function Object() {} + return function(prototype) { + if (isObject(prototype)) { + Object.prototype = prototype; + var result = new Object; + Object.prototype = null; + } + return result || root.Object(); + }; +}()); + +export default baseCreate; diff --git a/internal/baseDelay.js b/internal/baseDelay.js new file mode 100644 index 0000000000..65b0bf5450 --- /dev/null +++ b/internal/baseDelay.js @@ -0,0 +1,24 @@ +import baseSlice from './baseSlice'; +import isFunction from '../lang/isFunction'; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * The base implementation of `_.delay` and `_.defer` which accepts an index + * of where to slice the arguments to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Object} args The `arguments` object to slice and provide to `func`. + * @returns {number} Returns the timer id. + */ +function baseDelay(func, wait, args, fromIndex) { + if (!isFunction(func)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { func.apply(undefined, baseSlice(args, fromIndex)); }, wait); +} + +export default baseDelay; diff --git a/internal/baseDifference.js b/internal/baseDifference.js new file mode 100644 index 0000000000..5e37d12ff3 --- /dev/null +++ b/internal/baseDifference.js @@ -0,0 +1,52 @@ +import baseIndexOf from './baseIndexOf'; +import cacheIndexOf from './cacheIndexOf'; +import createCache from './createCache'; + +/** + * The base implementation of `_.difference` which accepts a single array + * of values to exclude. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @returns {Array} Returns the new array of filtered values. + */ +function baseDifference(array, values) { + var length = array ? array.length : 0, + result = []; + + if (!length) { + return result; + } + var index = -1, + indexOf = baseIndexOf, + isCommon = true, + cache = isCommon && values.length >= 200 && createCache(values), + valuesLength = values.length; + + if (cache) { + indexOf = cacheIndexOf; + isCommon = false; + values = cache; + } + outer: + while (++index < length) { + var value = array[index]; + + if (isCommon && value === value) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === value) { + continue outer; + } + } + result.push(value); + } + else if (indexOf(values, value) < 0) { + result.push(value); + } + } + return result; +} + +export default baseDifference; diff --git a/internal/baseEach.js b/internal/baseEach.js new file mode 100644 index 0000000000..6ac1c58b9d --- /dev/null +++ b/internal/baseEach.js @@ -0,0 +1,30 @@ +import baseForOwn from './baseForOwn'; +import isLength from './isLength'; +import toObject from './toObject'; + +/** + * The base implementation of `_.forEach` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object|string} Returns `collection`. + */ +function baseEach(collection, iteratee) { + var length = collection ? collection.length : 0; + if (!isLength(length)) { + return baseForOwn(collection, iteratee); + } + var index = -1, + iterable = toObject(collection); + + while (++index < length) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; +} + +export default baseEach; diff --git a/internal/baseEachRight.js b/internal/baseEachRight.js new file mode 100644 index 0000000000..abf09aab8c --- /dev/null +++ b/internal/baseEachRight.js @@ -0,0 +1,28 @@ +import baseForOwnRight from './baseForOwnRight'; +import isLength from './isLength'; +import toObject from './toObject'; + +/** + * The base implementation of `_.forEachRight` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object|string} Returns `collection`. + */ +function baseEachRight(collection, iteratee) { + var length = collection ? collection.length : 0; + if (!isLength(length)) { + return baseForOwnRight(collection, iteratee); + } + var iterable = toObject(collection); + while (length--) { + if (iteratee(iterable[length], length, iterable) === false) { + break; + } + } + return collection; +} + +export default baseEachRight; diff --git a/internal/baseEvery.js b/internal/baseEvery.js new file mode 100644 index 0000000000..979a9792a4 --- /dev/null +++ b/internal/baseEvery.js @@ -0,0 +1,22 @@ +import baseEach from './baseEach'; + +/** + * The base implementation of `_.every` without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ +function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; +} + +export default baseEvery; diff --git a/internal/baseFilter.js b/internal/baseFilter.js new file mode 100644 index 0000000000..15cc005344 --- /dev/null +++ b/internal/baseFilter.js @@ -0,0 +1,22 @@ +import baseEach from './baseEach'; + +/** + * The base implementation of `_.filter` without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ +function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function(value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; +} + +export default baseFilter; diff --git a/internal/baseFind.js b/internal/baseFind.js new file mode 100644 index 0000000000..dcd576a7a6 --- /dev/null +++ b/internal/baseFind.js @@ -0,0 +1,25 @@ +/** + * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, + * without support for callback shorthands and `this` binding, which iterates + * over `collection` using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} collection The collection to search. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @param {boolean} [retKey] Specify returning the key of the found element + * instead of the element itself. + * @returns {*} Returns the found element or its key, else `undefined`. + */ +function baseFind(collection, predicate, eachFunc, retKey) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = retKey ? key : value; + return false; + } + }); + return result; +} + +export default baseFind; diff --git a/internal/baseFlatten.js b/internal/baseFlatten.js new file mode 100644 index 0000000000..6dc272b710 --- /dev/null +++ b/internal/baseFlatten.js @@ -0,0 +1,45 @@ +import isArguments from '../lang/isArguments'; +import isArray from '../lang/isArray'; +import isLength from './isLength'; +import isObjectLike from './isObjectLike'; + +/** + * The base implementation of `_.flatten` with added support for restricting + * flattening and specifying the start index. + * + * @private + * @param {Array} array The array to flatten. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param {boolean} [isStrict] Restrict flattening to arrays and `arguments` objects. + * @param {number} [fromIndex=0] The index to start from. + * @returns {Array} Returns the new flattened array. + */ +function baseFlatten(array, isDeep, isStrict, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index]; + + if (isObjectLike(value) && isLength(value.length) && (isArray(value) || isArguments(value))) { + if (isDeep) { + // Recursively flatten arrays (susceptible to call stack limits). + value = baseFlatten(value, isDeep, isStrict); + } + var valIndex = -1, + valLength = value.length; + + result.length += valLength; + while (++valIndex < valLength) { + result[++resIndex] = value[valIndex]; + } + } else if (!isStrict) { + result[++resIndex] = value; + } + } + return result; +} + +export default baseFlatten; diff --git a/internal/baseFor.js b/internal/baseFor.js new file mode 100644 index 0000000000..e53819df94 --- /dev/null +++ b/internal/baseFor.js @@ -0,0 +1,30 @@ +import toObject from './toObject'; + +/** + * The base implementation of `baseForIn` and `baseForOwn` which iterates + * over `object` properties returned by `keysFunc` invoking `iteratee` for + * each property. Iterator functions may exit iteration early by explicitly + * returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ +function baseFor(object, iteratee, keysFunc) { + var index = -1, + iterable = toObject(object), + props = keysFunc(object), + length = props.length; + + while (++index < length) { + var key = props[index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; +} + +export default baseFor; diff --git a/internal/baseForIn.js b/internal/baseForIn.js new file mode 100644 index 0000000000..b9b56f82db --- /dev/null +++ b/internal/baseForIn.js @@ -0,0 +1,17 @@ +import baseFor from './baseFor'; +import keysIn from '../object/keysIn'; + +/** + * The base implementation of `_.forIn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ +function baseForIn(object, iteratee) { + return baseFor(object, iteratee, keysIn); +} + +export default baseForIn; diff --git a/internal/baseForOwn.js b/internal/baseForOwn.js new file mode 100644 index 0000000000..2b60b8bb47 --- /dev/null +++ b/internal/baseForOwn.js @@ -0,0 +1,17 @@ +import baseFor from './baseFor'; +import keys from '../object/keys'; + +/** + * The base implementation of `_.forOwn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ +function baseForOwn(object, iteratee) { + return baseFor(object, iteratee, keys); +} + +export default baseForOwn; diff --git a/internal/baseForOwnRight.js b/internal/baseForOwnRight.js new file mode 100644 index 0000000000..00dcc37348 --- /dev/null +++ b/internal/baseForOwnRight.js @@ -0,0 +1,17 @@ +import baseForRight from './baseForRight'; +import keys from '../object/keys'; + +/** + * The base implementation of `_.forOwnRight` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ +function baseForOwnRight(object, iteratee) { + return baseForRight(object, iteratee, keys); +} + +export default baseForOwnRight; diff --git a/internal/baseForRight.js b/internal/baseForRight.js new file mode 100644 index 0000000000..84444331d6 --- /dev/null +++ b/internal/baseForRight.js @@ -0,0 +1,27 @@ +import toObject from './toObject'; + +/** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ +function baseForRight(object, iteratee, keysFunc) { + var iterable = toObject(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[length]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; +} + +export default baseForRight; diff --git a/internal/baseFunctions.js b/internal/baseFunctions.js new file mode 100644 index 0000000000..9247482043 --- /dev/null +++ b/internal/baseFunctions.js @@ -0,0 +1,27 @@ +import isFunction from '../lang/isFunction'; + +/** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from those provided. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the new array of filtered property names. + */ +function baseFunctions(object, props) { + var index = -1, + length = props.length, + resIndex = -1, + result = []; + + while (++index < length) { + var key = props[index]; + if (isFunction(object[key])) { + result[++resIndex] = key; + } + } + return result; +} + +export default baseFunctions; diff --git a/internal/baseIndexOf.js b/internal/baseIndexOf.js new file mode 100644 index 0000000000..d7fe970f5f --- /dev/null +++ b/internal/baseIndexOf.js @@ -0,0 +1,27 @@ +import indexOfNaN from './indexOfNaN'; + +/** + * The base implementation of `_.indexOf` without support for binary searches. + * + * @private + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function baseIndexOf(array, value, fromIndex) { + if (value !== value) { + return indexOfNaN(array, fromIndex); + } + var index = (fromIndex || 0) - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; +} + +export default baseIndexOf; diff --git a/internal/baseInvoke.js b/internal/baseInvoke.js new file mode 100644 index 0000000000..9aa6fcb97b --- /dev/null +++ b/internal/baseInvoke.js @@ -0,0 +1,28 @@ +import baseEach from './baseEach'; +import isLength from './isLength'; + +/** + * The base implementation of `_.invoke` which requires additional arguments + * to be provided as an array of arguments rather than individually. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|string} methodName The name of the method to invoke or + * the function invoked per iteration. + * @param {Array} [args] The arguments to invoke the method with. + * @returns {Array} Returns the array of results. + */ +function baseInvoke(collection, methodName, args) { + var index = -1, + isFunc = typeof methodName == 'function', + length = collection ? collection.length : 0, + result = isLength(length) ? Array(length) : []; + + baseEach(collection, function(value) { + var func = isFunc ? methodName : (value != null && value[methodName]); + result[++index] = func ? func.apply(value, args) : undefined; + }); + return result; +} + +export default baseInvoke; diff --git a/internal/baseIsEqual.js b/internal/baseIsEqual.js new file mode 100644 index 0000000000..5e8e35abf6 --- /dev/null +++ b/internal/baseIsEqual.js @@ -0,0 +1,34 @@ +import baseIsEqualDeep from './baseIsEqualDeep'; + +/** + * The base implementation of `_.isEqual` without support for `this` binding + * `customizer` functions. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isWhere] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ +function baseIsEqual(value, other, customizer, isWhere, stackA, stackB) { + // Exit early for identical values. + if (value === other) { + // Treat `+0` vs. `-0` as not equal. + return value !== 0 || (1 / value == 1 / other); + } + var valType = typeof value, + othType = typeof other; + + // Exit early for unlike primitive values. + if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') || + value == null || other == null) { + // Return `false` unless both values are `NaN`. + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, baseIsEqual, customizer, isWhere, stackA, stackB); +} + +export default baseIsEqual; diff --git a/internal/baseIsEqualDeep.js b/internal/baseIsEqualDeep.js new file mode 100644 index 0000000000..e7ac95141f --- /dev/null +++ b/internal/baseIsEqualDeep.js @@ -0,0 +1,101 @@ +import equalArrays from './equalArrays'; +import equalByTag from './equalByTag'; +import equalObjects from './equalObjects'; +import isArray from '../lang/isArray'; +import isTypedArray from '../lang/isTypedArray'; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + objectTag = '[object Object]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing objects. + * @param {boolean} [isWhere] Specify performing partial comparisons. + * @param {Array} [stackA=[]] Tracks traversed `value` objects. + * @param {Array} [stackB=[]] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function baseIsEqualDeep(object, other, equalFunc, customizer, isWhere, stackA, stackB) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = arrayTag, + othTag = arrayTag; + + if (!objIsArr) { + objTag = objToString.call(object); + if (objTag == argsTag) { + objTag = objectTag; + } else if (objTag != objectTag) { + objIsArr = isTypedArray(object); + } + } + if (!othIsArr) { + othTag = objToString.call(other); + if (othTag == argsTag) { + othTag = objectTag; + } else if (othTag != objectTag) { + othIsArr = isTypedArray(other); + } + } + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && !(objIsArr || objIsObj)) { + return equalByTag(object, other, objTag); + } + var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (valWrapped || othWrapped) { + return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isWhere, stackA, stackB); + } + if (!isSameTag) { + return false; + } + // Assume cyclic values are equal. + // For more information on detecting circular references see https://es5.github.io/#JO. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == object) { + return stackB[length] == other; + } + } + // Add `object` and `other` to the stack of traversed objects. + stackA.push(object); + stackB.push(other); + + var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isWhere, stackA, stackB); + + stackA.pop(); + stackB.pop(); + + return result; +} + +export default baseIsEqualDeep; diff --git a/internal/baseIsMatch.js b/internal/baseIsMatch.js new file mode 100644 index 0000000000..4c34273505 --- /dev/null +++ b/internal/baseIsMatch.js @@ -0,0 +1,58 @@ +import baseIsEqual from './baseIsEqual'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * The base implementation of `_.isMatch` without support for callback + * shorthands or `this` binding. + * + * @private + * @param {Object} source The object to inspect. + * @param {Array} props The source property names to match. + * @param {Array} values The source values to match. + * @param {Array} strictCompareFlags Strict comparison flags for source values. + * @param {Function} [customizer] The function to customize comparing objects. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ +function baseIsMatch(object, props, values, strictCompareFlags, customizer) { + var length = props.length; + if (object == null) { + return !length; + } + var index = -1, + noCustomizer = !customizer; + + while (++index < length) { + if ((noCustomizer && strictCompareFlags[index]) + ? values[index] !== object[props[index]] + : !hasOwnProperty.call(object, props[index]) + ) { + return false; + } + } + index = -1; + while (++index < length) { + var key = props[index]; + if (noCustomizer && strictCompareFlags[index]) { + var result = hasOwnProperty.call(object, key); + } else { + var objValue = object[key], + srcValue = values[index]; + + result = customizer ? customizer(objValue, srcValue, key) : undefined; + if (typeof result == 'undefined') { + result = baseIsEqual(srcValue, objValue, customizer, true); + } + } + if (!result) { + return false; + } + } + return true; +} + +export default baseIsMatch; diff --git a/internal/baseMap.js b/internal/baseMap.js new file mode 100644 index 0000000000..11242f02e6 --- /dev/null +++ b/internal/baseMap.js @@ -0,0 +1,20 @@ +import baseEach from './baseEach'; + +/** + * The base implementation of `_.map` without support for callback shorthands + * or `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ +function baseMap(collection, iteratee) { + var result = []; + baseEach(collection, function(value, key, collection) { + result.push(iteratee(value, key, collection)); + }); + return result; +} + +export default baseMap; diff --git a/internal/baseMatches.js b/internal/baseMatches.js new file mode 100644 index 0000000000..b81853380f --- /dev/null +++ b/internal/baseMatches.js @@ -0,0 +1,51 @@ +import baseClone from './baseClone'; +import baseIsMatch from './baseIsMatch'; +import isStrictComparable from './isStrictComparable'; +import keys from '../object/keys'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * The base implementation of `_.matches` which supports specifying whether + * `source` should be cloned. + * + * @private + * @param {Object} source The object of property values to match. + * @param {boolean} [isCloned] Specify cloning the source object. + * @returns {Function} Returns the new function. + */ +function baseMatches(source, isCloned) { + var props = keys(source), + length = props.length; + + if (length == 1) { + var key = props[0], + value = source[key]; + + if (isStrictComparable(value)) { + return function(object) { + return object != null && value === object[key] && hasOwnProperty.call(object, key); + }; + } + } + if (isCloned) { + source = baseClone(source, true); + } + var values = Array(length), + strictCompareFlags = Array(length); + + while (length--) { + value = source[props[length]]; + values[length] = value; + strictCompareFlags[length] = isStrictComparable(value); + } + return function(object) { + return baseIsMatch(object, props, values, strictCompareFlags); + }; +} + +export default baseMatches; diff --git a/internal/baseMerge.js b/internal/baseMerge.js new file mode 100644 index 0000000000..1ec0f9ec6e --- /dev/null +++ b/internal/baseMerge.js @@ -0,0 +1,45 @@ +import arrayEach from './arrayEach'; +import baseForOwn from './baseForOwn'; +import baseMergeDeep from './baseMergeDeep'; +import isArray from '../lang/isArray'; +import isLength from './isLength'; +import isObjectLike from './isObjectLike'; +import isTypedArray from '../lang/isTypedArray'; + +/** + * The base implementation of `_.merge` without support for argument juggling, + * multiple sources, and `this` binding `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} [customizer] The function to customize merging properties. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {Object} Returns the destination object. + */ +function baseMerge(object, source, customizer, stackA, stackB) { + var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source)); + + (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) { + if (isObjectLike(srcValue)) { + stackA || (stackA = []); + stackB || (stackB = []); + return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); + } + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = typeof result == 'undefined'; + + if (isCommon) { + result = srcValue; + } + if ((isSrcArr || typeof result != 'undefined') && + (isCommon || (result === result ? result !== value : value === value))) { + object[key] = result; + } + }); + return object; +} + +export default baseMerge; diff --git a/internal/baseMergeDeep.js b/internal/baseMergeDeep.js new file mode 100644 index 0000000000..d1e2894f13 --- /dev/null +++ b/internal/baseMergeDeep.js @@ -0,0 +1,64 @@ +import arrayCopy from './arrayCopy'; +import isArguments from '../lang/isArguments'; +import isArray from '../lang/isArray'; +import isLength from './isLength'; +import isPlainObject from '../lang/isPlainObject'; +import isTypedArray from '../lang/isTypedArray'; +import toPlainObject from '../lang/toPlainObject'; + +/** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize merging properties. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { + var length = stackA.length, + srcValue = source[key]; + + while (length--) { + if (stackA[length] == srcValue) { + object[key] = stackB[length]; + return; + } + } + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = typeof result == 'undefined'; + + if (isCommon) { + result = srcValue; + if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) { + result = isArray(value) + ? value + : (value ? arrayCopy(value) : []); + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + result = isArguments(value) + ? toPlainObject(value) + : (isPlainObject(value) ? value : {}); + } + } + // Add the source value to the stack of traversed objects and associate + // it with its merged value. + stackA.push(srcValue); + stackB.push(result); + + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); + } else if (result === result ? result !== value : value === value) { + object[key] = result; + } +} + +export default baseMergeDeep; diff --git a/internal/baseProperty.js b/internal/baseProperty.js new file mode 100644 index 0000000000..17322fe3e3 --- /dev/null +++ b/internal/baseProperty.js @@ -0,0 +1,14 @@ +/** + * The base implementation of `_.property` which does not coerce `key` to a string. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; +} + +export default baseProperty; diff --git a/internal/basePullAt.js b/internal/basePullAt.js new file mode 100644 index 0000000000..54302200b6 --- /dev/null +++ b/internal/basePullAt.js @@ -0,0 +1,35 @@ +import baseAt from './baseAt'; +import baseCompareAscending from './baseCompareAscending'; +import isIndex from './isIndex'; + +/** Used for native method references. */ +var arrayProto = Array.prototype; + +/** Native method references. */ +var splice = arrayProto.splice; + +/** + * The base implementation of `_.pullAt` without support for individual + * index arguments. + * + * @private + * @param {Array} array The array to modify. + * @param {number[]} indexes The indexes of elements to remove. + * @returns {Array} Returns the new array of removed elements. + */ +function basePullAt(array, indexes) { + var length = indexes.length, + result = baseAt(array, indexes); + + indexes.sort(baseCompareAscending); + while (length--) { + var index = parseFloat(indexes[length]); + if (index != previous && isIndex(index)) { + var previous = index; + splice.call(array, index, 1); + } + } + return result; +} + +export default basePullAt; diff --git a/internal/baseRandom.js b/internal/baseRandom.js new file mode 100644 index 0000000000..c474454ff5 --- /dev/null +++ b/internal/baseRandom.js @@ -0,0 +1,20 @@ +/** Native method references. */ +var floor = Math.floor; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeRandom = Math.random; + +/** + * The base implementation of `_.random` without support for argument juggling + * and returning floating-point numbers. + * + * @private + * @param {number} min The minimum possible value. + * @param {number} max The maximum possible value. + * @returns {number} Returns the random number. + */ +function baseRandom(min, max) { + return min + floor(nativeRandom() * (max - min + 1)); +} + +export default baseRandom; diff --git a/internal/baseReduce.js b/internal/baseReduce.js new file mode 100644 index 0000000000..d841838881 --- /dev/null +++ b/internal/baseReduce.js @@ -0,0 +1,24 @@ +/** + * The base implementation of `_.reduce` and `_.reduceRight` without support + * for callback shorthands or `this` binding, which iterates over `collection` + * using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initFromCollection Specify using the first or last element + * of `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ +function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initFromCollection + ? (initFromCollection = false, value) + : iteratee(accumulator, value, index, collection) + }); + return accumulator; +} + +export default baseReduce; diff --git a/internal/baseSetData.js b/internal/baseSetData.js new file mode 100644 index 0000000000..c2364b97a3 --- /dev/null +++ b/internal/baseSetData.js @@ -0,0 +1,17 @@ +import identity from '../utility/identity'; +import metaMap from './metaMap'; + +/** + * The base implementation of `setData` without support for hot loop detection. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ +var baseSetData = !metaMap ? identity : function(func, data) { + metaMap.set(func, data); + return func; +}; + +export default baseSetData; diff --git a/internal/baseSlice.js b/internal/baseSlice.js new file mode 100644 index 0000000000..e89e7439f7 --- /dev/null +++ b/internal/baseSlice.js @@ -0,0 +1,31 @@ +/** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ +function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + start = start == null ? 0 : (+start || 0); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (typeof end == 'undefined' || end > length) ? length : (+end || 0); + if (end < 0) { + end += length; + } + length = start > end ? 0 : (end - start); + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; +} + +export default baseSlice; diff --git a/internal/baseSome.js b/internal/baseSome.js new file mode 100644 index 0000000000..b6f0a3c713 --- /dev/null +++ b/internal/baseSome.js @@ -0,0 +1,23 @@ +import baseEach from './baseEach'; + +/** + * The base implementation of `_.some` without support for callback shorthands + * or `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ +function baseSome(collection, predicate) { + var result; + + baseEach(collection, function(value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; +} + +export default baseSome; diff --git a/internal/baseSortBy.js b/internal/baseSortBy.js new file mode 100644 index 0000000000..26df3cdc94 --- /dev/null +++ b/internal/baseSortBy.js @@ -0,0 +1,21 @@ +/** + * The base implementation of `_.sortBy` and `_.sortByAll` which uses `comparer` + * to define the sort order of `array` and replaces criteria objects with their + * corresponding values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ +function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; +} + +export default baseSortBy; diff --git a/internal/baseToString.js b/internal/baseToString.js new file mode 100644 index 0000000000..25c63d3564 --- /dev/null +++ b/internal/baseToString.js @@ -0,0 +1,16 @@ +/** + * Converts `value` to a string if it is not one. An empty string is returned + * for `null` or `undefined` values. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + if (typeof value == 'string') { + return value; + } + return value == null ? '' : (value + ''); +} + +export default baseToString; diff --git a/internal/baseUniq.js b/internal/baseUniq.js new file mode 100644 index 0000000000..1bd8f328b4 --- /dev/null +++ b/internal/baseUniq.js @@ -0,0 +1,57 @@ +import baseIndexOf from './baseIndexOf'; +import cacheIndexOf from './cacheIndexOf'; +import createCache from './createCache'; + +/** + * The base implementation of `_.uniq` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The function invoked per iteration. + * @returns {Array} Returns the new duplicate-value-free array. + */ +function baseUniq(array, iteratee) { + var index = -1, + indexOf = baseIndexOf, + length = array.length, + isCommon = true, + isLarge = isCommon && length >= 200, + seen = isLarge && createCache(), + result = []; + + if (seen) { + indexOf = cacheIndexOf; + isCommon = false; + } else { + isLarge = false; + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value, index, array) : value; + + if (isCommon && value === value) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } + else if (indexOf(seen, computed) < 0) { + if (iteratee || isLarge) { + seen.push(computed); + } + result.push(value); + } + } + return result; +} + +export default baseUniq; diff --git a/internal/baseValues.js b/internal/baseValues.js new file mode 100644 index 0000000000..5b2434303f --- /dev/null +++ b/internal/baseValues.js @@ -0,0 +1,22 @@ +/** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * returned by `keysFunc`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ +function baseValues(object, props) { + var index = -1, + length = props.length, + result = Array(length); + + while (++index < length) { + result[index] = object[props[index]]; + } + return result; +} + +export default baseValues; diff --git a/internal/baseWrapperValue.js b/internal/baseWrapperValue.js new file mode 100644 index 0000000000..b6a9f81790 --- /dev/null +++ b/internal/baseWrapperValue.js @@ -0,0 +1,37 @@ +import LazyWrapper from './LazyWrapper'; + +/** Used for native method references. */ +var arrayProto = Array.prototype; + +/** Native method references. */ +var push = arrayProto.push; + +/** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to peform to resolve the unwrapped value. + * @returns {*} Returns the resolved unwrapped value. + */ +function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + var index = -1, + length = actions.length; + + while (++index < length) { + var args = [result], + action = actions[index]; + + push.apply(args, action.args); + result = action.func.apply(action.thisArg, args); + } + return result; +} + +export default baseWrapperValue; diff --git a/internal/binaryIndex.js b/internal/binaryIndex.js new file mode 100644 index 0000000000..984162bf51 --- /dev/null +++ b/internal/binaryIndex.js @@ -0,0 +1,40 @@ +import binaryIndexBy from './binaryIndexBy'; +import identity from '../utility/identity'; + +/** Used as references for the maximum length and index of an array. */ +var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + +/** + * Performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest, instead + * of the lowest, index at which a value should be inserted into `array`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ +function binaryIndex(array, value, retHighest) { + var low = 0, + high = array ? array.length : low; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if (retHighest ? (computed <= value) : (computed < value)) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return binaryIndexBy(array, value, identity, retHighest); +} + +export default binaryIndex; diff --git a/internal/binaryIndexBy.js b/internal/binaryIndexBy.js new file mode 100644 index 0000000000..3e07e22465 --- /dev/null +++ b/internal/binaryIndexBy.js @@ -0,0 +1,54 @@ +/** Native method references. */ +var floor = Math.floor; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMin = Math.min; + +/** Used as references for the maximum length and index of an array. */ +var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1; + +/** + * This function is like `binaryIndex` except that it invokes `iteratee` for + * `value` and each element of `array` to compute their sort ranking. The + * iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The function invoked per iteration. + * @param {boolean} [retHighest] Specify returning the highest, instead + * of the lowest, index at which a value should be inserted into `array`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ +function binaryIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array ? array.length : 0, + valIsNaN = value !== value, + valIsUndef = typeof value == 'undefined'; + + while (low < high) { + var mid = floor((low + high) / 2), + computed = iteratee(array[mid]), + isReflexive = computed === computed; + + if (valIsNaN) { + var setLow = isReflexive || retHighest; + } else if (valIsUndef) { + setLow = isReflexive && (retHighest || typeof computed != 'undefined'); + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); +} + +export default binaryIndexBy; diff --git a/internal/bindCallback.js b/internal/bindCallback.js new file mode 100644 index 0000000000..e6965cfbe0 --- /dev/null +++ b/internal/bindCallback.js @@ -0,0 +1,39 @@ +import identity from '../utility/identity'; + +/** + * A specialized version of `baseCallback` which only supports `this` binding + * and specifying the number of arguments to provide to `func`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ +function bindCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + if (typeof thisArg == 'undefined') { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + case 5: return function(value, other, key, object, source) { + return func.call(thisArg, value, other, key, object, source); + }; + } + return function() { + return func.apply(thisArg, arguments); + }; +} + +export default bindCallback; diff --git a/internal/bufferClone.js b/internal/bufferClone.js new file mode 100644 index 0000000000..b9b6321e93 --- /dev/null +++ b/internal/bufferClone.js @@ -0,0 +1,56 @@ +import constant from '../utility/constant'; +import isNative from '../lang/isNative'; +import root from './root'; + +/** Native method references. */ +var ArrayBuffer = isNative(ArrayBuffer = root.ArrayBuffer) && ArrayBuffer, + bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice, + floor = Math.floor, + Uint8Array = isNative(Uint8Array = root.Uint8Array) && Uint8Array; + +/** Used to clone array buffers. */ +var Float64Array = (function() { + // Safari 5 errors when using an array buffer to initialize a typed array + // where the array buffer's `byteLength` is not a multiple of the typed + // array's `BYTES_PER_ELEMENT`. + try { + var func = isNative(func = root.Float64Array) && func, + result = new func(new ArrayBuffer(10), 0, 1) && func; + } catch(e) {} + return result; +}()); + +/** Used as the size, in bytes, of each `Float64Array` element. */ +var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0; + +/** + * Creates a clone of the given array buffer. + * + * @private + * @param {ArrayBuffer} buffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ +function bufferClone(buffer) { + return bufferSlice.call(buffer, 0); +} +if (!bufferSlice) { + // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`. + bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) { + var byteLength = buffer.byteLength, + floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0, + offset = floatLength * FLOAT64_BYTES_PER_ELEMENT, + result = new ArrayBuffer(byteLength); + + if (floatLength) { + var view = new Float64Array(result, 0, floatLength); + view.set(new Float64Array(buffer, 0, floatLength)); + } + if (byteLength != offset) { + view = new Uint8Array(result, offset); + view.set(new Uint8Array(buffer, offset)); + } + return result; + }; +} + +export default bufferClone; diff --git a/internal/cacheIndexOf.js b/internal/cacheIndexOf.js new file mode 100644 index 0000000000..700fc3caa0 --- /dev/null +++ b/internal/cacheIndexOf.js @@ -0,0 +1,19 @@ +import isObject from '../lang/isObject'; + +/** + * Checks if `value` is in `cache` mimicking the return signature of + * `_.indexOf` by returning `0` if the value is found, else `-1`. + * + * @private + * @param {Object} cache The cache to search. + * @param {*} value The value to search for. + * @returns {number} Returns `0` if `value` is found, else `-1`. + */ +function cacheIndexOf(cache, value) { + var data = cache.data, + result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value]; + + return result ? 0 : -1; +} + +export default cacheIndexOf; diff --git a/internal/cachePush.js b/internal/cachePush.js new file mode 100644 index 0000000000..93a60cfe7e --- /dev/null +++ b/internal/cachePush.js @@ -0,0 +1,20 @@ +import isObject from '../lang/isObject'; + +/** + * Adds `value` to the cache. + * + * @private + * @name push + * @memberOf SetCache + * @param {*} value The value to cache. + */ +function cachePush(value) { + var data = this.data; + if (typeof value == 'string' || isObject(value)) { + data.set.add(value); + } else { + data.hash[value] = true; + } +} + +export default cachePush; diff --git a/internal/charAtCallback.js b/internal/charAtCallback.js new file mode 100644 index 0000000000..9ff01d81c9 --- /dev/null +++ b/internal/charAtCallback.js @@ -0,0 +1,12 @@ +/** + * Used by `_.max` and `_.min` as the default callback for string values. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the code unit of the first character of the string. + */ +function charAtCallback(string) { + return string.charCodeAt(0); +} + +export default charAtCallback; diff --git a/internal/charsLeftIndex.js b/internal/charsLeftIndex.js new file mode 100644 index 0000000000..cfe5fc2e6b --- /dev/null +++ b/internal/charsLeftIndex.js @@ -0,0 +1,18 @@ +/** + * Used by `_.trim` and `_.trimLeft` to get the index of the first character + * of `string` that is not found in `chars`. + * + * @private + * @param {string} string The string to inspect. + * @param {string} chars The characters to find. + * @returns {number} Returns the index of the first character not found in `chars`. + */ +function charsLeftIndex(string, chars) { + var index = -1, + length = string.length; + + while (++index < length && chars.indexOf(string.charAt(index)) > -1) {} + return index; +} + +export default charsLeftIndex; diff --git a/internal/charsRightIndex.js b/internal/charsRightIndex.js new file mode 100644 index 0000000000..2cc4396373 --- /dev/null +++ b/internal/charsRightIndex.js @@ -0,0 +1,17 @@ +/** + * Used by `_.trim` and `_.trimRight` to get the index of the last character + * of `string` that is not found in `chars`. + * + * @private + * @param {string} string The string to inspect. + * @param {string} chars The characters to find. + * @returns {number} Returns the index of the last character not found in `chars`. + */ +function charsRightIndex(string, chars) { + var index = string.length; + + while (index-- && chars.indexOf(string.charAt(index)) > -1) {} + return index; +} + +export default charsRightIndex; diff --git a/internal/compareAscending.js b/internal/compareAscending.js new file mode 100644 index 0000000000..c1ed564873 --- /dev/null +++ b/internal/compareAscending.js @@ -0,0 +1,16 @@ +import baseCompareAscending from './baseCompareAscending'; + +/** + * Used by `_.sortBy` to compare transformed elements of a collection and stable + * sort them in ascending order. + * + * @private + * @param {Object} object The object to compare to `other`. + * @param {Object} other The object to compare to `object`. + * @returns {number} Returns the sort order indicator for `object`. + */ +function compareAscending(object, other) { + return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index); +} + +export default compareAscending; diff --git a/internal/compareMultipleAscending.js b/internal/compareMultipleAscending.js new file mode 100644 index 0000000000..eb24af85c1 --- /dev/null +++ b/internal/compareMultipleAscending.js @@ -0,0 +1,34 @@ +import baseCompareAscending from './baseCompareAscending'; + +/** + * Used by `_.sortByAll` to compare multiple properties of each element + * in a collection and stable sort them in ascending order. + * + * @private + * @param {Object} object The object to compare to `other`. + * @param {Object} other The object to compare to `object`. + * @returns {number} Returns the sort order indicator for `object`. + */ +function compareMultipleAscending(object, other) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length; + + while (++index < length) { + var result = baseCompareAscending(objCriteria[index], othCriteria[index]); + if (result) { + return result; + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://code.google.com/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; +} + +export default compareMultipleAscending; diff --git a/internal/composeArgs.js b/internal/composeArgs.js new file mode 100644 index 0000000000..8ec286f116 --- /dev/null +++ b/internal/composeArgs.js @@ -0,0 +1,34 @@ +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array|Object} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @returns {Array} Returns the new array of composed arguments. + */ +function composeArgs(args, partials, holders) { + var holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), + leftIndex = -1, + leftLength = partials.length, + result = Array(argsLength + leftLength); + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + while (argsLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; +} + +export default composeArgs; diff --git a/internal/composeArgsRight.js b/internal/composeArgsRight.js new file mode 100644 index 0000000000..f00e57c65b --- /dev/null +++ b/internal/composeArgsRight.js @@ -0,0 +1,36 @@ +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array|Object} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @returns {Array} Returns the new array of composed arguments. + */ +function composeArgsRight(args, partials, holders) { + var holdersIndex = -1, + holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), + rightIndex = -1, + rightLength = partials.length, + result = Array(argsLength + rightLength); + + while (++argsIndex < argsLength) { + result[argsIndex] = args[argsIndex]; + } + var pad = argsIndex; + while (++rightIndex < rightLength) { + result[pad + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + result[pad + holders[holdersIndex]] = args[argsIndex++]; + } + return result; +} + +export default composeArgsRight; diff --git a/internal/createAggregator.js b/internal/createAggregator.js new file mode 100644 index 0000000000..1600f21f2f --- /dev/null +++ b/internal/createAggregator.js @@ -0,0 +1,38 @@ +import baseCallback from './baseCallback'; +import baseEach from './baseEach'; +import isArray from '../lang/isArray'; + +/** + * Creates a function that aggregates a collection, creating an accumulator + * object composed from the results of running each element in the collection + * through an iteratee. The `setter` sets the keys and values of the accumulator + * object. If `initializer` is provided initializes the accumulator object. + * + * @private + * @param {Function} setter The function to set keys and values of the accumulator object. + * @param {Function} [initializer] The function to initialize the accumulator object. + * @returns {Function} Returns the new aggregator function. + */ +function createAggregator(setter, initializer) { + return function(collection, iteratee, thisArg) { + var result = initializer ? initializer() : {}; + iteratee = baseCallback(iteratee, thisArg, 3); + + if (isArray(collection)) { + var index = -1, + length = collection.length; + + while (++index < length) { + var value = collection[index]; + setter(result, value, iteratee(value, index, collection), collection); + } + } else { + baseEach(collection, function(value, key, collection) { + setter(result, value, iteratee(value, key, collection), collection); + }); + } + return result; + }; +} + +export default createAggregator; diff --git a/internal/createAssigner.js b/internal/createAssigner.js new file mode 100644 index 0000000000..46d3a03e18 --- /dev/null +++ b/internal/createAssigner.js @@ -0,0 +1,40 @@ +import bindCallback from './bindCallback'; +import isIterateeCall from './isIterateeCall'; + +/** + * Creates a function that assigns properties of source object(s) to a given + * destination object. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ +function createAssigner(assigner) { + return function() { + var length = arguments.length, + object = arguments[0]; + + if (length < 2 || object == null) { + return object; + } + if (length > 3 && isIterateeCall(arguments[1], arguments[2], arguments[3])) { + length = 2; + } + // Juggle arguments. + if (length > 3 && typeof arguments[length - 2] == 'function') { + var customizer = bindCallback(arguments[--length - 1], arguments[length--], 5); + } else if (length > 2 && typeof arguments[length - 1] == 'function') { + customizer = arguments[--length]; + } + var index = 0; + while (++index < length) { + var source = arguments[index]; + if (source) { + assigner(object, source, customizer); + } + } + return object; + }; +} + +export default createAssigner; diff --git a/internal/createBindWrapper.js b/internal/createBindWrapper.js new file mode 100644 index 0000000000..99a175ddb0 --- /dev/null +++ b/internal/createBindWrapper.js @@ -0,0 +1,21 @@ +import createCtorWrapper from './createCtorWrapper'; + +/** + * Creates a function that wraps `func` and invokes it with the `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to bind. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new bound function. + */ +function createBindWrapper(func, thisArg) { + var Ctor = createCtorWrapper(func); + + function wrapper() { + return (this instanceof wrapper ? Ctor : func).apply(thisArg, arguments); + } + return wrapper; +} + +export default createBindWrapper; diff --git a/internal/createCache.js b/internal/createCache.js new file mode 100644 index 0000000000..8f395da280 --- /dev/null +++ b/internal/createCache.js @@ -0,0 +1,23 @@ +import SetCache from './SetCache'; +import constant from '../utility/constant'; +import isNative from '../lang/isNative'; +import root from './root'; + +/** Native method references. */ +var Set = isNative(Set = root.Set) && Set; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate; + +/** + * Creates a `Set` cache object to optimize linear searches of large arrays. + * + * @private + * @param {Array} [values] The values to cache. + * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. + */ +var createCache = !(nativeCreate && Set) ? constant(null) : function(values) { + return new SetCache(values); +}; + +export default createCache; diff --git a/internal/createCompounder.js b/internal/createCompounder.js new file mode 100644 index 0000000000..144dd09a63 --- /dev/null +++ b/internal/createCompounder.js @@ -0,0 +1,26 @@ +import deburr from '../string/deburr'; +import words from '../string/words'; + +/** + * Creates a function that produces compound words out of the words in a + * given string. + * + * @private + * @param {Function} callback The function to combine each word. + * @returns {Function} Returns the new compounder function. + */ +function createCompounder(callback) { + return function(string) { + var index = -1, + array = words(deburr(string)), + length = array.length, + result = ''; + + while (++index < length) { + result = callback(result, array[index], index); + } + return result; + }; +} + +export default createCompounder; diff --git a/internal/createCtorWrapper.js b/internal/createCtorWrapper.js new file mode 100644 index 0000000000..33ddcb010d --- /dev/null +++ b/internal/createCtorWrapper.js @@ -0,0 +1,23 @@ +import baseCreate from './baseCreate'; +import isObject from '../lang/isObject'; + +/** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ +function createCtorWrapper(Ctor) { + return function() { + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, arguments); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; +} + +export default createCtorWrapper; diff --git a/internal/createExtremum.js b/internal/createExtremum.js new file mode 100644 index 0000000000..a2b6393b3b --- /dev/null +++ b/internal/createExtremum.js @@ -0,0 +1,38 @@ +import baseCallback from './baseCallback'; +import charAtCallback from './charAtCallback'; +import extremumBy from './extremumBy'; +import isArray from '../lang/isArray'; +import isIterateeCall from './isIterateeCall'; +import isString from '../lang/isString'; +import toIterable from './toIterable'; + +/** + * Creates a function that gets the extremum value of a collection. + * + * @private + * @param {Function} arrayFunc The function to get the extremum value from an array. + * @param {boolean} [isMin] Specify returning the minimum, instead of the maximum, + * extremum value. + * @returns {Function} Returns the new extremum function. + */ +function createExtremum(arrayFunc, isMin) { + return function(collection, iteratee, thisArg) { + if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + iteratee = null; + } + var noIteratee = iteratee == null; + + iteratee = noIteratee ? iteratee : baseCallback(iteratee, thisArg, 3); + if (noIteratee) { + var isArr = isArray(collection); + if (!isArr && isString(collection)) { + iteratee = charAtCallback; + } else { + return arrayFunc(isArr ? collection : toIterable(collection)); + } + } + return extremumBy(collection, iteratee, isMin); + }; +} + +export default createExtremum; diff --git a/internal/createHybridWrapper.js b/internal/createHybridWrapper.js new file mode 100644 index 0000000000..97ddc14e2c --- /dev/null +++ b/internal/createHybridWrapper.js @@ -0,0 +1,104 @@ +import arrayCopy from './arrayCopy'; +import composeArgs from './composeArgs'; +import composeArgsRight from './composeArgsRight'; +import createCtorWrapper from './createCtorWrapper'; +import reorder from './reorder'; +import replaceHolders from './replaceHolders'; + +/** Used to compose bitmasks for wrapper metadata. */ +var BIND_FLAG = 1, + BIND_KEY_FLAG = 2, + CURRY_BOUND_FLAG = 4, + CURRY_FLAG = 8, + CURRY_RIGHT_FLAG = 16, + PARTIAL_FLAG = 32, + PARTIAL_RIGHT_FLAG = 64, + ARY_FLAG = 256; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * Creates a function that wraps `func` and invokes it with optional `this` + * binding of, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ +function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & ARY_FLAG, + isBind = bitmask & BIND_FLAG, + isBindKey = bitmask & BIND_KEY_FLAG, + isCurry = bitmask & CURRY_FLAG, + isCurryBound = bitmask & CURRY_BOUND_FLAG, + isCurryRight = bitmask & CURRY_RIGHT_FLAG; + + var Ctor = !isBindKey && createCtorWrapper(func), + key = func; + + function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it to other functions. + var length = arguments.length, + index = length, + args = Array(length); + + while (index--) { + args[index] = arguments[index]; + } + if (partials) { + args = composeArgs(args, partials, holders); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight); + } + if (isCurry || isCurryRight) { + var placeholder = wrapper.placeholder, + argsHolders = replaceHolders(args, placeholder); + + length -= argsHolders.length; + if (length < arity) { + var newArgPos = argPos ? arrayCopy(argPos) : null, + newArity = nativeMax(arity - length, 0), + newsHolders = isCurry ? argsHolders : null, + newHoldersRight = isCurry ? null : argsHolders, + newPartials = isCurry ? args : null, + newPartialsRight = isCurry ? null : args; + + bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); + + if (!isCurryBound) { + bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); + } + var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity); + result.placeholder = placeholder; + return result; + } + } + var thisBinding = isBind ? thisArg : this; + if (isBindKey) { + func = thisBinding[key]; + } + if (argPos) { + args = reorder(args, argPos); + } + if (isAry && ary < args.length) { + args.length = ary; + } + return (this instanceof wrapper ? (Ctor || createCtorWrapper(func)) : func).apply(thisBinding, args); + } + return wrapper; +} + +export default createHybridWrapper; diff --git a/internal/createPad.js b/internal/createPad.js new file mode 100644 index 0000000000..97c2bfddd0 --- /dev/null +++ b/internal/createPad.js @@ -0,0 +1,34 @@ +import baseToString from './baseToString'; +import repeat from '../string/repeat'; +import root from './root'; + +/** Native method references. */ +var ceil = Math.ceil; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsFinite = root.isFinite; + +/** + * Creates the pad required for `string` based on the given padding length. + * The `chars` string may be truncated if the number of padding characters + * exceeds the padding length. + * + * @private + * @param {string} string The string to create padding for. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the pad for `string`. + */ +function createPad(string, length, chars) { + var strLength = string.length; + length = +length; + + if (strLength >= length || !nativeIsFinite(length)) { + return ''; + } + var padLength = length - strLength; + chars = chars == null ? ' ' : baseToString(chars); + return repeat(chars, ceil(padLength / chars.length)).slice(0, padLength); +} + +export default createPad; diff --git a/internal/createPartialWrapper.js b/internal/createPartialWrapper.js new file mode 100644 index 0000000000..9c6e8b710d --- /dev/null +++ b/internal/createPartialWrapper.js @@ -0,0 +1,42 @@ +import createCtorWrapper from './createCtorWrapper'; + +/** Used to compose bitmasks for wrapper metadata. */ +var BIND_FLAG = 1; + +/** + * Creates a function that wraps `func` and invokes it with the optional `this` + * binding of `thisArg` and the `partials` prepended to those provided to + * the wrapper. + * + * @private + * @param {Function} func The function to partially apply arguments to. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to the new function. + * @returns {Function} Returns the new bound function. + */ +function createPartialWrapper(func, bitmask, thisArg, partials) { + var isBind = bitmask & BIND_FLAG, + Ctor = createCtorWrapper(func); + + function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it `func`. + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(argsLength + leftLength); + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + return (this instanceof wrapper ? Ctor : func).apply(isBind ? thisArg : this, args); + } + return wrapper; +} + +export default createPartialWrapper; diff --git a/internal/createWrapper.js b/internal/createWrapper.js new file mode 100644 index 0000000000..59027949e3 --- /dev/null +++ b/internal/createWrapper.js @@ -0,0 +1,87 @@ +import baseSetData from './baseSetData'; +import createBindWrapper from './createBindWrapper'; +import createHybridWrapper from './createHybridWrapper'; +import createPartialWrapper from './createPartialWrapper'; +import getData from './getData'; +import isFunction from '../lang/isFunction'; +import mergeData from './mergeData'; +import setData from './setData'; + +/** Used to compose bitmasks for wrapper metadata. */ +var BIND_FLAG = 1, + BIND_KEY_FLAG = 2, + PARTIAL_FLAG = 32, + PARTIAL_RIGHT_FLAG = 64; + +/** Used as the `TypeError` message for "Functions" methods. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. + * The bitmask may be composed of the following flags: + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ +function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & BIND_KEY_FLAG; + if (!isBindKey && !isFunction(func)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); + partials = holders = null; + } + length -= (holders ? holders.length : 0); + if (bitmask & PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = null; + } + var data = !isBindKey && getData(func), + newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity]; + + if (data && data !== true) { + mergeData(newData, data); + bitmask = newData[1]; + arity = newData[9]; + } + newData[9] = arity == null + ? (isBindKey ? 0 : func.length) + : (nativeMax(arity - length, 0) || 0); + + if (bitmask == BIND_FLAG) { + var result = createBindWrapper(newData[0], newData[2]); + } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) { + result = createPartialWrapper.apply(null, newData); + } else { + result = createHybridWrapper.apply(null, newData); + } + var setter = data ? baseSetData : setData; + return setter(result, newData); +} + +export default createWrapper; diff --git a/internal/deburrLetter.js b/internal/deburrLetter.js new file mode 100644 index 0000000000..a0eab9f067 --- /dev/null +++ b/internal/deburrLetter.js @@ -0,0 +1,33 @@ +/** Used to map latin-1 supplementary letters to basic latin letters. */ +var deburredLetters = { + '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', + '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', + '\xc7': 'C', '\xe7': 'c', + '\xd0': 'D', '\xf0': 'd', + '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', + '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', + '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', + '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', + '\xd1': 'N', '\xf1': 'n', + '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', + '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', + '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', + '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', + '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', + '\xc6': 'Ae', '\xe6': 'ae', + '\xde': 'Th', '\xfe': 'th', + '\xdf': 'ss' +}; + +/** + * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. + * + * @private + * @param {string} letter The matched letter to deburr. + * @returns {string} Returns the deburred letter. + */ +function deburrLetter(letter) { + return deburredLetters[letter]; +} + +export default deburrLetter; diff --git a/internal/equalArrays.js b/internal/equalArrays.js new file mode 100644 index 0000000000..2766c64ada --- /dev/null +++ b/internal/equalArrays.js @@ -0,0 +1,54 @@ +/** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing arrays. + * @param {boolean} [isWhere] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ +function equalArrays(array, other, equalFunc, customizer, isWhere, stackA, stackB) { + var index = -1, + arrLength = array.length, + othLength = other.length, + result = true; + + if (arrLength != othLength && !(isWhere && othLength > arrLength)) { + return false; + } + // Deep compare the contents, ignoring non-numeric properties. + while (result && ++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + result = undefined; + if (customizer) { + result = isWhere + ? customizer(othValue, arrValue, index) + : customizer(arrValue, othValue, index); + } + if (typeof result == 'undefined') { + // Recursively compare arrays (susceptible to call stack limits). + if (isWhere) { + var othIndex = othLength; + while (othIndex--) { + othValue = other[othIndex]; + result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB); + if (result) { + break; + } + } + } else { + result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isWhere, stackA, stackB); + } + } + } + return !!result; +} + +export default equalArrays; diff --git a/internal/equalByTag.js b/internal/equalByTag.js new file mode 100644 index 0000000000..4e71b64d5c --- /dev/null +++ b/internal/equalByTag.js @@ -0,0 +1,51 @@ +import baseToString from './baseToString'; + +/** `Object#toString` result references. */ +var boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + numberTag = '[object Number]', + regexpTag = '[object RegExp]', + stringTag = '[object String]'; + +/** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} value The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalByTag(object, other, tag) { + switch (tag) { + case boolTag: + case dateTag: + // Coerce dates and booleans to numbers, dates to milliseconds and booleans + // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. + return +object == +other; + + case errorTag: + return object.name == other.name && object.message == other.message; + + case numberTag: + // Treat `NaN` vs. `NaN` as equal. + return (object != +object) + ? other != +other + // But, treat `-0` vs. `+0` as not equal. + : (object == 0 ? ((1 / object) == (1 / other)) : object == +other); + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings primitives and string + // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. + return object == baseToString(other); + } + return false; +} + +export default equalByTag; diff --git a/internal/equalObjects.js b/internal/equalObjects.js new file mode 100644 index 0000000000..93f7bea854 --- /dev/null +++ b/internal/equalObjects.js @@ -0,0 +1,72 @@ +import keys from '../object/keys'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isWhere] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalObjects(object, other, equalFunc, customizer, isWhere, stackA, stackB) { + var objProps = keys(object), + objLength = objProps.length, + othProps = keys(other), + othLength = othProps.length; + + if (objLength != othLength && !isWhere) { + return false; + } + var hasCtor, + index = -1; + + while (++index < objLength) { + var key = objProps[index], + result = hasOwnProperty.call(other, key); + + if (result) { + var objValue = object[key], + othValue = other[key]; + + result = undefined; + if (customizer) { + result = isWhere + ? customizer(othValue, objValue, key) + : customizer(objValue, othValue, key); + } + if (typeof result == 'undefined') { + // Recursively compare objects (susceptible to call stack limits). + result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isWhere, stackA, stackB); + } + } + if (!result) { + return false; + } + hasCtor || (hasCtor = key == 'constructor'); + } + if (!hasCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) { + return false; + } + } + return true; +} + +export default equalObjects; diff --git a/internal/escapeHtmlChar.js b/internal/escapeHtmlChar.js new file mode 100644 index 0000000000..58e9f4ac83 --- /dev/null +++ b/internal/escapeHtmlChar.js @@ -0,0 +1,22 @@ +/** Used to map characters to HTML entities. */ +var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' +}; + +/** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ +function escapeHtmlChar(chr) { + return htmlEscapes[chr]; +} + +export default escapeHtmlChar; diff --git a/internal/escapeStringChar.js b/internal/escapeStringChar.js new file mode 100644 index 0000000000..073f458ccf --- /dev/null +++ b/internal/escapeStringChar.js @@ -0,0 +1,23 @@ +/** Used to escape characters for inclusion in compiled string literals. */ +var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\u2028': 'u2028', + '\u2029': 'u2029' +}; + +/** + * Used by `_.template` to escape characters for inclusion in compiled + * string literals. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ +function escapeStringChar(chr) { + return '\\' + stringEscapes[chr]; +} + +export default escapeStringChar; diff --git a/internal/extremumBy.js b/internal/extremumBy.js new file mode 100644 index 0000000000..9d66150ad9 --- /dev/null +++ b/internal/extremumBy.js @@ -0,0 +1,34 @@ +import baseEach from './baseEach'; + +/** Used as references for `-Infinity` and `Infinity`. */ +var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, + POSITIVE_INFINITY = Number.POSITIVE_INFINITY; + +/** + * Gets the extremum value of `collection` invoking `iteratee` for each value + * in `collection` to generate the criterion by which the value is ranked. + * The `iteratee` is invoked with three arguments; (value, index, collection). + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {boolean} [isMin] Specify returning the minimum, instead of the + * maximum, extremum value. + * @returns {*} Returns the extremum value. + */ +function extremumBy(collection, iteratee, isMin) { + var exValue = isMin ? POSITIVE_INFINITY : NEGATIVE_INFINITY, + computed = exValue, + result = computed; + + baseEach(collection, function(value, index, collection) { + var current = iteratee(value, index, collection); + if ((isMin ? current < computed : current > computed) || (current === exValue && current === result)) { + computed = current; + result = value; + } + }); + return result; +} + +export default extremumBy; diff --git a/internal/getData.js b/internal/getData.js new file mode 100644 index 0000000000..7dc75375a1 --- /dev/null +++ b/internal/getData.js @@ -0,0 +1,15 @@ +import metaMap from './metaMap'; +import noop from '../utility/noop'; + +/** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ +var getData = !metaMap ? noop : function(func) { + return metaMap.get(func); +}; + +export default getData; diff --git a/internal/getView.js b/internal/getView.js new file mode 100644 index 0000000000..14c5a25577 --- /dev/null +++ b/internal/getView.js @@ -0,0 +1,33 @@ +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max, + nativeMin = Math.min; + +/** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} [transforms] The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ +function getView(start, end, transforms) { + var index = -1, + length = transforms ? transforms.length : 0; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': start += size; break; + case 'dropRight': end -= size; break; + case 'take': end = nativeMin(end, start + size); break; + case 'takeRight': start = nativeMax(start, end - size); break; + } + } + return { 'start': start, 'end': end }; +} + +export default getView; diff --git a/internal/indexOfNaN.js b/internal/indexOfNaN.js new file mode 100644 index 0000000000..f6472d996d --- /dev/null +++ b/internal/indexOfNaN.js @@ -0,0 +1,24 @@ +/** + * Gets the index at which the first occurrence of `NaN` is found in `array`. + * If `fromRight` is provided elements of `array` are iterated from right to left. + * + * @private + * @param {Array} array The array to search. + * @param {number} [fromIndex] The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched `NaN`, else `-1`. + */ +function indexOfNaN(array, fromIndex, fromRight) { + var length = array.length, + index = fromRight ? (fromIndex || length) : ((fromIndex || 0) - 1); + + while ((fromRight ? index-- : ++index < length)) { + var other = array[index]; + if (other !== other) { + return index; + } + } + return -1; +} + +export default indexOfNaN; diff --git a/internal/initCloneArray.js b/internal/initCloneArray.js new file mode 100644 index 0000000000..8e6d68296c --- /dev/null +++ b/internal/initCloneArray.js @@ -0,0 +1,26 @@ +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ +function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add array properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; +} + +export default initCloneArray; diff --git a/internal/initCloneByTag.js b/internal/initCloneByTag.js new file mode 100644 index 0000000000..3bd9ea6aee --- /dev/null +++ b/internal/initCloneByTag.js @@ -0,0 +1,64 @@ +import bufferClone from './bufferClone'; + +/** `Object#toString` result references. */ +var boolTag = '[object Boolean]', + dateTag = '[object Date]', + numberTag = '[object Number]', + regexpTag = '[object RegExp]', + stringTag = '[object String]'; + +var arrayBufferTag = '[object ArrayBuffer]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** Used to match `RegExp` flags from their coerced string values. */ +var reFlags = /\w*$/; + +/** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return bufferClone(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + var buffer = object.buffer; + return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + var result = new Ctor(object.source, reFlags.exec(object)); + result.lastIndex = object.lastIndex; + } + return result; +} + +export default initCloneByTag; diff --git a/internal/initCloneObject.js b/internal/initCloneObject.js new file mode 100644 index 0000000000..5d8afa2069 --- /dev/null +++ b/internal/initCloneObject.js @@ -0,0 +1,16 @@ +/** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ +function initCloneObject(object) { + var Ctor = object.constructor; + if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { + Ctor = Object; + } + return new Ctor; +} + +export default initCloneObject; diff --git a/internal/isBindable.js b/internal/isBindable.js new file mode 100644 index 0000000000..78fd050e5a --- /dev/null +++ b/internal/isBindable.js @@ -0,0 +1,38 @@ +import baseSetData from './baseSetData'; +import isNative from '../lang/isNative'; +import support from '../support'; + +/** Used to detect named functions. */ +var reFuncName = /^\s*function[ \n\r\t]+\w/; + +/** Used to detect functions containing a `this` reference. */ +var reThis = /\bthis\b/; + +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; + +/** + * Checks if `func` is eligible for `this` binding. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is eligible, else `false`. + */ +function isBindable(func) { + var result = !(support.funcNames ? func.name : support.funcDecomp); + + if (!result) { + var source = fnToString.call(func); + if (!support.funcNames) { + result = !reFuncName.test(source); + } + if (!result) { + // Check if `func` references the `this` keyword and store the result. + result = reThis.test(source) || isNative(func); + baseSetData(func, result); + } + } + return result; +} + +export default isBindable; diff --git a/internal/isIndex.js b/internal/isIndex.js new file mode 100644 index 0000000000..6df32fd139 --- /dev/null +++ b/internal/isIndex.js @@ -0,0 +1,22 @@ +/** + * Used as the maximum length of an array-like value. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength) + * for more details. + */ +var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + value = +value; + length = length == null ? MAX_SAFE_INTEGER : length; + return value > -1 && value % 1 == 0 && value < length; +} + +export default isIndex; diff --git a/internal/isIterateeCall.js b/internal/isIterateeCall.js new file mode 100644 index 0000000000..9e0164885f --- /dev/null +++ b/internal/isIterateeCall.js @@ -0,0 +1,28 @@ +import isIndex from './isIndex'; +import isLength from './isLength'; +import isObject from '../lang/isObject'; + +/** + * Checks if the provided arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. + */ +function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number') { + var length = object.length, + prereq = isLength(length) && isIndex(index, length); + } else { + prereq = type == 'string' && index in value; + } + return prereq && object[index] === value; +} + +export default isIterateeCall; diff --git a/internal/isLength.js b/internal/isLength.js new file mode 100644 index 0000000000..792f027fc9 --- /dev/null +++ b/internal/isLength.js @@ -0,0 +1,19 @@ +/** + * Used as the maximum length of an array-like value. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength) + * for more details. + */ +var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; + +/** + * Checks if `value` is a valid array-like length. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +export default isLength; diff --git a/internal/isObjectLike.js b/internal/isObjectLike.js new file mode 100644 index 0000000000..79e839485e --- /dev/null +++ b/internal/isObjectLike.js @@ -0,0 +1,12 @@ +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { + return (value && typeof value == 'object') || false; +} + +export default isObjectLike; diff --git a/internal/isSpace.js b/internal/isSpace.js new file mode 100644 index 0000000000..b9082a2125 --- /dev/null +++ b/internal/isSpace.js @@ -0,0 +1,14 @@ +/** + * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a + * character code is whitespace. + * + * @private + * @param {number} charCode The character code to inspect. + * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`. + */ +function isSpace(charCode) { + return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 || + (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279))); +} + +export default isSpace; diff --git a/internal/isStrictComparable.js b/internal/isStrictComparable.js new file mode 100644 index 0000000000..0b3a97bffd --- /dev/null +++ b/internal/isStrictComparable.js @@ -0,0 +1,15 @@ +import isObject from '../lang/isObject'; + +/** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ +function isStrictComparable(value) { + return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value)); +} + +export default isStrictComparable; diff --git a/internal/lazyClone.js b/internal/lazyClone.js new file mode 100644 index 0000000000..25daa93165 --- /dev/null +++ b/internal/lazyClone.js @@ -0,0 +1,28 @@ +import LazyWrapper from './LazyWrapper'; +import arrayCopy from './arrayCopy'; + +/** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ +function lazyClone() { + var actions = this.actions, + iteratees = this.iteratees, + views = this.views, + result = new LazyWrapper(this.wrapped); + + result.actions = actions ? arrayCopy(actions) : null; + result.dir = this.dir; + result.dropCount = this.dropCount; + result.filtered = this.filtered; + result.iteratees = iteratees ? arrayCopy(iteratees) : null; + result.takeCount = this.takeCount; + result.views = views ? arrayCopy(views) : null; + return result; +} + +export default lazyClone; diff --git a/internal/lazyReverse.js b/internal/lazyReverse.js new file mode 100644 index 0000000000..71ff549c0c --- /dev/null +++ b/internal/lazyReverse.js @@ -0,0 +1,20 @@ +import LazyWrapper from './LazyWrapper'; + +/** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ +function lazyReverse() { + var filtered = this.filtered, + result = filtered ? new LazyWrapper(this) : this.clone(); + + result.dir = this.dir * -1; + result.filtered = filtered; + return result; +} + +export default lazyReverse; diff --git a/internal/lazyValue.js b/internal/lazyValue.js new file mode 100644 index 0000000000..98689473e9 --- /dev/null +++ b/internal/lazyValue.js @@ -0,0 +1,71 @@ +import baseWrapperValue from './baseWrapperValue'; +import getView from './getView'; +import isArray from '../lang/isArray'; + +/** Used to indicate the type of lazy iteratees. */ +var LAZY_FILTER_FLAG = 0, + LAZY_MAP_FLAG = 1; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMin = Math.min; + +/** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ +function lazyValue() { + var array = this.wrapped.value(); + if (!isArray(array)) { + return baseWrapperValue(array, this.actions); + } + var dir = this.dir, + isRight = dir < 0, + length = array.length, + view = getView(0, length, this.views), + start = view.start, + end = view.end, + dropCount = this.dropCount, + takeCount = nativeMin(end - start, this.takeCount - dropCount), + index = isRight ? end : start - 1, + iteratees = this.iteratees, + iterLength = iteratees ? iteratees.length : 0, + resIndex = 0, + result = []; + + outer: + while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + computed = iteratee(value, index, array), + type = data.type; + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + if (dropCount) { + dropCount--; + } else { + result[resIndex++] = value; + } + } + return isRight ? result.reverse() : result; +} + +export default lazyValue; diff --git a/internal/mapDelete.js b/internal/mapDelete.js new file mode 100644 index 0000000000..6fce955009 --- /dev/null +++ b/internal/mapDelete.js @@ -0,0 +1,14 @@ +/** + * Removes `key` and its value from the cache. + * + * @private + * @name delete + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. + */ +function mapDelete(key) { + return this.has(key) && delete this.__data__[key]; +} + +export default mapDelete; diff --git a/internal/mapGet.js b/internal/mapGet.js new file mode 100644 index 0000000000..4f1913dec9 --- /dev/null +++ b/internal/mapGet.js @@ -0,0 +1,14 @@ +/** + * Gets the cached value for `key`. + * + * @private + * @name get + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to get. + * @returns {*} Returns the cached value. + */ +function mapGet(key) { + return key == '__proto__' ? undefined : this.__data__[key]; +} + +export default mapGet; diff --git a/internal/mapHas.js b/internal/mapHas.js new file mode 100644 index 0000000000..0bea8caae6 --- /dev/null +++ b/internal/mapHas.js @@ -0,0 +1,20 @@ +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Checks if a cached value for `key` exists. + * + * @private + * @name has + * @memberOf _.memoize.Cache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function mapHas(key) { + return key != '__proto__' && hasOwnProperty.call(this.__data__, key); +} + +export default mapHas; diff --git a/internal/mapSet.js b/internal/mapSet.js new file mode 100644 index 0000000000..e80ef6d85b --- /dev/null +++ b/internal/mapSet.js @@ -0,0 +1,18 @@ +/** + * Adds `value` to `key` of the cache. + * + * @private + * @name set + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to cache. + * @param {*} value The value to cache. + * @returns {Object} Returns the cache object. + */ +function mapSet(key, value) { + if (key != '__proto__') { + this.__data__[key] = value; + } + return this; +} + +export default mapSet; diff --git a/internal/mergeData.js b/internal/mergeData.js new file mode 100644 index 0000000000..909cdff228 --- /dev/null +++ b/internal/mergeData.js @@ -0,0 +1,99 @@ +import arrayCopy from './arrayCopy'; +import composeArgs from './composeArgs'; +import composeArgsRight from './composeArgsRight'; +import replaceHolders from './replaceHolders'; + +/** Used to compose bitmasks for wrapper metadata. */ +var BIND_FLAG = 1, + BIND_KEY_FLAG = 2, + CURRY_BOUND_FLAG = 4, + CURRY_RIGHT_FLAG = 16, + REARG_FLAG = 128, + ARY_FLAG = 256; + +/** Used as the internal argument placeholder. */ +var PLACEHOLDER = '__lodash_placeholder__'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMin = Math.min; + +/** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers required to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` + * augment function arguments, making the order in which they are executed important, + * preventing the merging of metadata. However, we make an exception for a safe + * common case where curried functions have `_.ary` and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ +function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask; + + var arityFlags = ARY_FLAG | REARG_FLAG, + bindFlags = BIND_FLAG | BIND_KEY_FLAG, + comboFlags = arityFlags | bindFlags | CURRY_BOUND_FLAG | CURRY_RIGHT_FLAG; + + var isAry = bitmask & ARY_FLAG && !(srcBitmask & ARY_FLAG), + isRearg = bitmask & REARG_FLAG && !(srcBitmask & REARG_FLAG), + argPos = (isRearg ? data : source)[7], + ary = (isAry ? data : source)[8]; + + var isCommon = !(bitmask >= REARG_FLAG && srcBitmask > bindFlags) && + !(bitmask > bindFlags && srcBitmask >= REARG_FLAG); + + var isCombo = (newBitmask >= arityFlags && newBitmask <= comboFlags) && + (bitmask < REARG_FLAG || ((isRearg || isAry) && argPos.length <= ary)); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = arrayCopy(value); + } + // Use source `ary` if it's smaller. + if (srcBitmask & ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; +} + +export default mergeData; diff --git a/internal/metaMap.js b/internal/metaMap.js new file mode 100644 index 0000000000..3f37f644f0 --- /dev/null +++ b/internal/metaMap.js @@ -0,0 +1,10 @@ +import isNative from '../lang/isNative'; +import root from './root'; + +/** Native method references. */ +var WeakMap = isNative(WeakMap = root.WeakMap) && WeakMap; + +/** Used to store function metadata. */ +var metaMap = WeakMap && new WeakMap; + +export default metaMap; diff --git a/internal/pickByArray.js b/internal/pickByArray.js new file mode 100644 index 0000000000..3abd48a1ce --- /dev/null +++ b/internal/pickByArray.js @@ -0,0 +1,28 @@ +import toObject from './toObject'; + +/** + * A specialized version of `_.pick` that picks `object` properties specified + * by the `props` array. + * + * @private + * @param {Object} object The source object. + * @param {string[]} props The property names to pick. + * @returns {Object} Returns the new object. + */ +function pickByArray(object, props) { + object = toObject(object); + + var index = -1, + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index]; + if (key in object) { + result[key] = object[key]; + } + } + return result; +} + +export default pickByArray; diff --git a/internal/pickByCallback.js b/internal/pickByCallback.js new file mode 100644 index 0000000000..63feb356cf --- /dev/null +++ b/internal/pickByCallback.js @@ -0,0 +1,22 @@ +import baseForIn from './baseForIn'; + +/** + * A specialized version of `_.pick` that picks `object` properties `predicate` + * returns truthy for. + * + * @private + * @param {Object} object The source object. + * @param {Function} predicate The function invoked per iteration. + * @returns {Object} Returns the new object. + */ +function pickByCallback(object, predicate) { + var result = {}; + baseForIn(object, function(value, key, object) { + if (predicate(value, key, object)) { + result[key] = value; + } + }); + return result; +} + +export default pickByCallback; diff --git a/internal/reEscape.js b/internal/reEscape.js new file mode 100644 index 0000000000..cd3729b18f --- /dev/null +++ b/internal/reEscape.js @@ -0,0 +1,4 @@ +/** Used to match template delimiters. */ +var reEscape = /<%-([\s\S]+?)%>/g; + +export default reEscape; diff --git a/internal/reEvaluate.js b/internal/reEvaluate.js new file mode 100644 index 0000000000..563964bf88 --- /dev/null +++ b/internal/reEvaluate.js @@ -0,0 +1,4 @@ +/** Used to match template delimiters. */ +var reEvaluate = /<%([\s\S]+?)%>/g; + +export default reEvaluate; diff --git a/internal/reInterpolate.js b/internal/reInterpolate.js new file mode 100644 index 0000000000..a3cdb20e9a --- /dev/null +++ b/internal/reInterpolate.js @@ -0,0 +1,4 @@ +/** Used to match template delimiters. */ +var reInterpolate = /<%=([\s\S]+?)%>/g; + +export default reInterpolate; diff --git a/internal/reorder.js b/internal/reorder.js new file mode 100644 index 0000000000..a31e032cc9 --- /dev/null +++ b/internal/reorder.js @@ -0,0 +1,29 @@ +import arrayCopy from './arrayCopy'; +import isIndex from './isIndex'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMin = Math.min; + +/** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ +function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = arrayCopy(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; +} + +export default reorder; diff --git a/internal/replaceHolders.js b/internal/replaceHolders.js new file mode 100644 index 0000000000..274726863e --- /dev/null +++ b/internal/replaceHolders.js @@ -0,0 +1,28 @@ +/** Used as the internal argument placeholder. */ +var PLACEHOLDER = '__lodash_placeholder__'; + +/** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ +function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + if (array[index] === placeholder) { + array[index] = PLACEHOLDER; + result[++resIndex] = index; + } + } + return result; +} + +export default replaceHolders; diff --git a/internal/root.js b/internal/root.js new file mode 100644 index 0000000000..c326966a85 --- /dev/null +++ b/internal/root.js @@ -0,0 +1,27 @@ +/** Used to determine if values are of the language type `Object`. */ +var objectTypes = { + 'function': true, + 'object': true +}; + +/** + * Used as a reference to the global object. + * + * The `this` value is used if it is the global object to avoid Greasemonkey's + * restricted `window` object, otherwise the `window` object is used. + */ +var root = (objectTypes[typeof window] && window !== (this && this.window)) ? window : this; + +/** Detect free variable `exports`. */ +var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + +/** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */ +var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; +if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) { + root = freeGlobal; +} + +export default root; diff --git a/internal/setData.js b/internal/setData.js new file mode 100644 index 0000000000..6bc08bbd1f --- /dev/null +++ b/internal/setData.js @@ -0,0 +1,41 @@ +import baseSetData from './baseSetData'; +import now from '../date/now'; + +/** Used to detect when a function becomes hot. */ +var HOT_COUNT = 150, + HOT_SPAN = 16; + +/** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity function + * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ +var setData = (function() { + var count = 0, + lastCalled = 0; + + return function(key, value) { + var stamp = now(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return key; + } + } else { + count = 0; + } + return baseSetData(key, value); + }; +}()); + +export default setData; diff --git a/internal/shimIsPlainObject.js b/internal/shimIsPlainObject.js new file mode 100644 index 0000000000..7299aaa7cb --- /dev/null +++ b/internal/shimIsPlainObject.js @@ -0,0 +1,51 @@ +import baseForIn from './baseForIn'; +import isObjectLike from './isObjectLike'; + +/** `Object#toString` result references. */ +var objectTag = '[object Object]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * A fallback implementation of `_.isPlainObject` which checks if `value` + * is an object created by the `Object` constructor or has a `[[Prototype]]` + * of `null`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + */ +function shimIsPlainObject(value) { + var Ctor; + + // Exit early for non `Object` objects. + if (!(isObjectLike(value) && objToString.call(value) == objectTag) || + (!hasOwnProperty.call(value, 'constructor') && + (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { + return false; + } + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + var result; + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + baseForIn(value, function(subValue, key) { + result = key; + }); + return typeof result == 'undefined' || hasOwnProperty.call(value, result); +} + +export default shimIsPlainObject; diff --git a/internal/shimKeys.js b/internal/shimKeys.js new file mode 100644 index 0000000000..b55beb1896 --- /dev/null +++ b/internal/shimKeys.js @@ -0,0 +1,42 @@ +import isArguments from '../lang/isArguments'; +import isArray from '../lang/isArray'; +import isIndex from './isIndex'; +import isLength from './isLength'; +import keysIn from '../object/keysIn'; +import support from '../support'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * A fallback implementation of `Object.keys` which creates an array of the + * own enumerable property names of `object`. + * + * @private + * @param {Object} object The object to inspect. + * @returns {Array} Returns the array of property names. + */ +function shimKeys(object) { + var props = keysIn(object), + propsLength = props.length, + length = propsLength && object.length; + + var allowIndexes = length && isLength(length) && + (isArray(object) || (support.nonEnumArgs && isArguments(object))); + + var index = -1, + result = []; + + while (++index < propsLength) { + var key = props[index]; + if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { + result.push(key); + } + } + return result; +} + +export default shimKeys; diff --git a/internal/sortedUniq.js b/internal/sortedUniq.js new file mode 100644 index 0000000000..6c14113d9b --- /dev/null +++ b/internal/sortedUniq.js @@ -0,0 +1,29 @@ +/** + * An implementation of `_.uniq` optimized for sorted arrays without support + * for callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The function invoked per iteration. + * @returns {Array} Returns the new duplicate-value-free array. + */ +function sortedUniq(array, iteratee) { + var seen, + index = -1, + length = array.length, + resIndex = -1, + result = []; + + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value, index, array) : value; + + if (!index || seen !== computed) { + seen = computed; + result[++resIndex] = value; + } + } + return result; +} + +export default sortedUniq; diff --git a/internal/toIterable.js b/internal/toIterable.js new file mode 100644 index 0000000000..e1cf811752 --- /dev/null +++ b/internal/toIterable.js @@ -0,0 +1,22 @@ +import isLength from './isLength'; +import isObject from '../lang/isObject'; +import values from '../object/values'; + +/** + * Converts `value` to an array-like object if it is not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array|Object} Returns the array-like object. + */ +function toIterable(value) { + if (value == null) { + return []; + } + if (!isLength(value.length)) { + return values(value); + } + return isObject(value) ? value : Object(value); +} + +export default toIterable; diff --git a/internal/toObject.js b/internal/toObject.js new file mode 100644 index 0000000000..93601057b7 --- /dev/null +++ b/internal/toObject.js @@ -0,0 +1,14 @@ +import isObject from '../lang/isObject'; + +/** + * Converts `value` to an object if it is not one. + * + * @private + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ +function toObject(value) { + return isObject(value) ? value : Object(value); +} + +export default toObject; diff --git a/internal/trimmedLeftIndex.js b/internal/trimmedLeftIndex.js new file mode 100644 index 0000000000..bfa0d8d1cc --- /dev/null +++ b/internal/trimmedLeftIndex.js @@ -0,0 +1,19 @@ +import isSpace from './isSpace'; + +/** + * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the first non-whitespace character. + */ +function trimmedLeftIndex(string) { + var index = -1, + length = string.length; + + while (++index < length && isSpace(string.charCodeAt(index))) {} + return index; +} + +export default trimmedLeftIndex; diff --git a/internal/trimmedRightIndex.js b/internal/trimmedRightIndex.js new file mode 100644 index 0000000000..dbaf539326 --- /dev/null +++ b/internal/trimmedRightIndex.js @@ -0,0 +1,18 @@ +import isSpace from './isSpace'; + +/** + * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the last non-whitespace character. + */ +function trimmedRightIndex(string) { + var index = string.length; + + while (index-- && isSpace(string.charCodeAt(index))) {} + return index; +} + +export default trimmedRightIndex; diff --git a/internal/unescapeHtmlChar.js b/internal/unescapeHtmlChar.js new file mode 100644 index 0000000000..ab3171e251 --- /dev/null +++ b/internal/unescapeHtmlChar.js @@ -0,0 +1,22 @@ +/** Used to map HTML entities to characters. */ +var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'", + '`': '`' +}; + +/** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ +function unescapeHtmlChar(chr) { + return htmlUnescapes[chr]; +} + +export default unescapeHtmlChar; diff --git a/lang.js b/lang.js new file mode 100644 index 0000000000..2a7709748c --- /dev/null +++ b/lang.js @@ -0,0 +1,53 @@ +import clone from './lang/clone'; +import cloneDeep from './lang/cloneDeep'; +import isArguments from './lang/isArguments'; +import isArray from './lang/isArray'; +import isBoolean from './lang/isBoolean'; +import isDate from './lang/isDate'; +import isElement from './lang/isElement'; +import isEmpty from './lang/isEmpty'; +import isEqual from './lang/isEqual'; +import isError from './lang/isError'; +import isFinite from './lang/isFinite'; +import isFunction from './lang/isFunction'; +import isMatch from './lang/isMatch'; +import isNaN from './lang/isNaN'; +import isNative from './lang/isNative'; +import isNull from './lang/isNull'; +import isNumber from './lang/isNumber'; +import isObject from './lang/isObject'; +import isPlainObject from './lang/isPlainObject'; +import isRegExp from './lang/isRegExp'; +import isString from './lang/isString'; +import isTypedArray from './lang/isTypedArray'; +import isUndefined from './lang/isUndefined'; +import toArray from './lang/toArray'; +import toPlainObject from './lang/toPlainObject'; + +export default { + 'clone': clone, + 'cloneDeep': cloneDeep, + 'isArguments': isArguments, + 'isArray': isArray, + 'isBoolean': isBoolean, + 'isDate': isDate, + 'isElement': isElement, + 'isEmpty': isEmpty, + 'isEqual': isEqual, + 'isError': isError, + 'isFinite': isFinite, + 'isFunction': isFunction, + 'isMatch': isMatch, + 'isNaN': isNaN, + 'isNative': isNative, + 'isNull': isNull, + 'isNumber': isNumber, + 'isObject': isObject, + 'isPlainObject': isPlainObject, + 'isRegExp': isRegExp, + 'isString': isString, + 'isTypedArray': isTypedArray, + 'isUndefined': isUndefined, + 'toArray': toArray, + 'toPlainObject': toPlainObject +}; diff --git a/lang/clone.js b/lang/clone.js new file mode 100644 index 0000000000..413d48d55e --- /dev/null +++ b/lang/clone.js @@ -0,0 +1,65 @@ +import baseClone from '../internal/baseClone'; +import bindCallback from '../internal/bindCallback'; +import isIterateeCall from '../internal/isIterateeCall'; + +/** + * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, + * otherwise they are assigned by reference. If `customizer` is provided it is + * invoked to produce the cloned values. If `customizer` returns `undefined` + * cloning is handled by the method instead. The `customizer` is bound to + * `thisArg` and invoked with two argument; (value [, index|key, object]). + * + * **Note:** This method is loosely based on the structured clone algorithm. + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm) + * for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {*} Returns the cloned value. + * @example + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * var shallow = _.clone(users); + * shallow[0] === users[0]; + * // => true + * + * var deep = _.clone(users, true); + * deep[0] === users[0]; + * // => false + * + * // using a customizer callback + * var body = _.clone(document.body, function(value) { + * return _.isElement(value) ? value.cloneNode(false) : undefined; + * }); + * + * body === document.body + * // => false + * body.nodeName + * // => BODY + * body.childNodes.length; + * // => 0 + */ +function clone(value, isDeep, customizer, thisArg) { + // Juggle arguments. + if (typeof isDeep != 'boolean' && isDeep != null) { + thisArg = customizer; + customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep; + isDeep = false; + } + customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1); + return baseClone(value, isDeep, customizer); +} + +export default clone; diff --git a/lang/cloneDeep.js b/lang/cloneDeep.js new file mode 100644 index 0000000000..483ea7ab24 --- /dev/null +++ b/lang/cloneDeep.js @@ -0,0 +1,52 @@ +import baseClone from '../internal/baseClone'; +import bindCallback from '../internal/bindCallback'; + +/** + * Creates a deep clone of `value`. If `customizer` is provided it is invoked + * to produce the cloned values. If `customizer` returns `undefined` cloning + * is handled by the method instead. The `customizer` is bound to `thisArg` + * and invoked with two argument; (value [, index|key, object]). + * + * **Note:** This method is loosely based on the structured clone algorithm. + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm) + * for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {*} Returns the deep cloned value. + * @example + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * var deep = _.cloneDeep(users); + * deep[0] === users[0]; + * // => false + * + * // using a customizer callback + * var el = _.cloneDeep(document.body, function(value) { + * return _.isElement(value) ? value.cloneNode(true) : undefined; + * }); + * + * body === document.body + * // => false + * body.nodeName + * // => BODY + * body.childNodes.length; + * // => 20 + */ +function cloneDeep(value, customizer, thisArg) { + customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1); + return baseClone(value, true, customizer); +} + +export default cloneDeep; diff --git a/lang/isArguments.js b/lang/isArguments.js new file mode 100644 index 0000000000..ee89f304d9 --- /dev/null +++ b/lang/isArguments.js @@ -0,0 +1,38 @@ +import isLength from '../internal/isLength'; +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is classified as an `arguments` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * (function() { return _.isArguments(arguments); })(); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +function isArguments(value) { + var length = isObjectLike(value) ? value.length : undefined; + return (isLength(length) && objToString.call(value) == argsTag) || false; +} + +export default isArguments; diff --git a/lang/isArray.js b/lang/isArray.js new file mode 100644 index 0000000000..d461d27971 --- /dev/null +++ b/lang/isArray.js @@ -0,0 +1,41 @@ +import isLength from '../internal/isLength'; +import isNative from './isNative'; +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var arrayTag = '[object Array]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray; + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * (function() { return _.isArray(arguments); })(); + * // => false + */ +var isArray = nativeIsArray || function(value) { + return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false; +}; + +export default isArray; diff --git a/lang/isBoolean.js b/lang/isBoolean.js new file mode 100644 index 0000000000..c1ae0c1ece --- /dev/null +++ b/lang/isBoolean.js @@ -0,0 +1,36 @@ +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var boolTag = '[object Boolean]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ +function isBoolean(value) { + return (value === true || value === false || isObjectLike(value) && objToString.call(value) == boolTag) || false; +} + +export default isBoolean; diff --git a/lang/isDate.js b/lang/isDate.js new file mode 100644 index 0000000000..a5bbc84ca4 --- /dev/null +++ b/lang/isDate.js @@ -0,0 +1,36 @@ +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var dateTag = '[object Date]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ +function isDate(value) { + return (isObjectLike(value) && objToString.call(value) == dateTag) || false; +} + +export default isDate; diff --git a/lang/isElement.js b/lang/isElement.js new file mode 100644 index 0000000000..c24386e843 --- /dev/null +++ b/lang/isElement.js @@ -0,0 +1,42 @@ +import isObjectLike from '../internal/isObjectLike'; +import isPlainObject from './isPlainObject'; +import support from '../support'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is a DOM element. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ +function isElement(value) { + return (value && value.nodeType === 1 && isObjectLike(value) && + objToString.call(value).indexOf('Element') > -1) || false; +} +// Fallback for environments without DOM support. +if (!support.dom) { + isElement = function(value) { + return (value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value)) || false; + }; +} + +export default isElement; diff --git a/lang/isEmpty.js b/lang/isEmpty.js new file mode 100644 index 0000000000..8a6adffa47 --- /dev/null +++ b/lang/isEmpty.js @@ -0,0 +1,48 @@ +import isArguments from './isArguments'; +import isArray from './isArray'; +import isFunction from './isFunction'; +import isLength from '../internal/isLength'; +import isObjectLike from '../internal/isObjectLike'; +import isString from './isString'; +import keys from '../object/keys'; + +/** + * Checks if a value is empty. A value is considered empty unless it is an + * `arguments` object, array, string, or jQuery-like collection with a length + * greater than `0` or an object with own enumerable properties. + * + * @static + * @memberOf _ + * @category Lang + * @param {Array|Object|string} value The value to inspect. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ +function isEmpty(value) { + if (value == null) { + return true; + } + var length = value.length; + if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) || + (isObjectLike(value) && isFunction(value.splice)))) { + return !length; + } + return !keys(value).length; +} + +export default isEmpty; diff --git a/lang/isEqual.js b/lang/isEqual.js new file mode 100644 index 0000000000..507b6109d7 --- /dev/null +++ b/lang/isEqual.js @@ -0,0 +1,54 @@ +import baseIsEqual from '../internal/baseIsEqual'; +import bindCallback from '../internal/bindCallback'; +import isStrictComparable from '../internal/isStrictComparable'; + +/** + * Performs a deep comparison between two values to determine if they are + * equivalent. If `customizer` is provided it is invoked to compare values. + * If `customizer` returns `undefined` comparisons are handled by the method + * instead. The `customizer` is bound to `thisArg` and invoked with three + * arguments; (value, other [, index|key]). + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Functions and DOM nodes + * are **not** supported. Provide a customizer function to extend support + * for comparing other values. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparing values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'user': 'fred' }; + * var other = { 'user': 'fred' }; + * + * object == other; + * // => false + * + * _.isEqual(object, other); + * // => true + * + * // using a customizer callback + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqual(array, other, function(value, other) { + * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; + * }); + * // => true + */ +function isEqual(value, other, customizer, thisArg) { + customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3); + if (!customizer && isStrictComparable(value) && isStrictComparable(other)) { + return value === other; + } + var result = customizer ? customizer(value, other) : undefined; + return typeof result == 'undefined' ? baseIsEqual(value, other, customizer) : !!result; +} + +export default isEqual; diff --git a/lang/isError.js b/lang/isError.js new file mode 100644 index 0000000000..79d55bb862 --- /dev/null +++ b/lang/isError.js @@ -0,0 +1,37 @@ +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var errorTag = '[object Error]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ +function isError(value) { + return (isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag) || false; +} + +export default isError; diff --git a/lang/isFinite.js b/lang/isFinite.js new file mode 100644 index 0000000000..faf3e9c480 --- /dev/null +++ b/lang/isFinite.js @@ -0,0 +1,41 @@ +import isNative from './isNative'; +import root from '../internal/root'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsFinite = root.isFinite, + nativeNumIsFinite = isNative(nativeNumIsFinite = Number.isFinite) && nativeNumIsFinite; + +/** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on ES `Number.isFinite`. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite) + * for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(10); + * // => true + * + * _.isFinite('10'); + * // => false + * + * _.isFinite(true); + * // => false + * + * _.isFinite(Object(10)); + * // => false + * + * _.isFinite(Infinity); + * // => false + */ +var isFinite = nativeNumIsFinite || function(value) { + return typeof value == 'number' && nativeIsFinite(value); +}; + +export default isFinite; diff --git a/lang/isFunction.js b/lang/isFunction.js new file mode 100644 index 0000000000..66b24c032a --- /dev/null +++ b/lang/isFunction.js @@ -0,0 +1,51 @@ +import isNative from './isNative'; +import root from '../internal/root'; + +/** `Object#toString` result references. */ +var funcTag = '[object Function]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** Native method references. */ +var Uint8Array = isNative(Uint8Array = root.Uint8Array) && Uint8Array; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + // Avoid a Chakra JIT bug in compatibility modes of IE 11. + // See https://github.com/jashkenas/underscore/issues/1621 for more details. + return typeof value == 'function' || false; +} +// Fallback for environments that return incorrect `typeof` operator results. +if (isFunction(/x/) || (Uint8Array && !isFunction(Uint8Array))) { + isFunction = function(value) { + // The use of `Object#toString` avoids issues with the `typeof` operator + // in older versions of Chrome and Safari which return 'function' for regexes + // and Safari 8 equivalents which return 'object' for typed array constructors. + return objToString.call(value) == funcTag; + }; +} + +export default isFunction; diff --git a/lang/isMatch.js b/lang/isMatch.js new file mode 100644 index 0000000000..6e017717bb --- /dev/null +++ b/lang/isMatch.js @@ -0,0 +1,74 @@ +import baseIsMatch from '../internal/baseIsMatch'; +import bindCallback from '../internal/bindCallback'; +import isStrictComparable from '../internal/isStrictComparable'; +import keys from '../object/keys'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Performs a deep comparison between `object` and `source` to determine if + * `object` contains equivalent property values. If `customizer` is provided + * it is invoked to compare values. If `customizer` returns `undefined` + * comparisons are handled by the method instead. The `customizer` is bound + * to `thisArg` and invoked with three arguments; (value, other, index|key). + * + * **Note:** This method supports comparing properties of arrays, booleans, + * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions + * and DOM nodes are **not** supported. Provide a customizer function to extend + * support for comparing other values. + * + * @static + * @memberOf _ + * @category Lang + * @param {Object} source The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparing values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.isMatch(object, { 'age': 40 }); + * // => true + * + * _.isMatch(object, { 'age': 36 }); + * // => false + * + * // using a customizer callback + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatch(object, source, function(value, other) { + * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; + * }); + * // => true + */ +function isMatch(object, source, customizer, thisArg) { + var props = keys(source), + length = props.length; + + customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3); + if (!customizer && length == 1) { + var key = props[0], + value = source[key]; + + if (isStrictComparable(value)) { + return object != null && value === object[key] && hasOwnProperty.call(object, key); + } + } + var values = Array(length), + strictCompareFlags = Array(length); + + while (length--) { + value = values[length] = source[props[length]]; + strictCompareFlags[length] = isStrictComparable(value); + } + return baseIsMatch(object, props, values, strictCompareFlags, customizer); +} + +export default isMatch; diff --git a/lang/isNaN.js b/lang/isNaN.js new file mode 100644 index 0000000000..6c3bec80a4 --- /dev/null +++ b/lang/isNaN.js @@ -0,0 +1,35 @@ +import isNumber from './isNumber'; + +/** + * Checks if `value` is `NaN`. + * + * **Note:** This method is not the same as native `isNaN` which returns `true` + * for `undefined` and other non-numeric values. See the [ES5 spec](https://es5.github.io/#x15.1.2.4) + * for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ +function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some host objects in IE. + return isNumber(value) && value != +value; +} + +export default isNaN; diff --git a/lang/isNative.js b/lang/isNative.js new file mode 100644 index 0000000000..0a45cc022d --- /dev/null +++ b/lang/isNative.js @@ -0,0 +1,55 @@ +import escapeRegExp from '../string/escapeRegExp'; +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var funcTag = '[object Function]'; + +/** Used to detect host constructors (Safari > 5). */ +var reHostCtor = /^\[object .+?Constructor\]$/; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** Used to detect if a method is native. */ +var reNative = RegExp('^' + + escapeRegExp(objToString) + .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ +function isNative(value) { + if (value == null) { + return false; + } + if (objToString.call(value) == funcTag) { + return reNative.test(fnToString.call(value)); + } + return (isObjectLike(value) && reHostCtor.test(value)) || false; +} + +export default isNative; diff --git a/lang/isNull.js b/lang/isNull.js new file mode 100644 index 0000000000..f66645fdb5 --- /dev/null +++ b/lang/isNull.js @@ -0,0 +1,21 @@ +/** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ +function isNull(value) { + return value === null; +} + +export default isNull; diff --git a/lang/isNumber.js b/lang/isNumber.js new file mode 100644 index 0000000000..818b027ac4 --- /dev/null +++ b/lang/isNumber.js @@ -0,0 +1,42 @@ +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var numberTag = '[object Number]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified + * as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isNumber(8.4); + * // => true + * + * _.isNumber(NaN); + * // => true + * + * _.isNumber('8.4'); + * // => false + */ +function isNumber(value) { + return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag) || false; +} + +export default isNumber; diff --git a/lang/isObject.js b/lang/isObject.js new file mode 100644 index 0000000000..c66e88d985 --- /dev/null +++ b/lang/isObject.js @@ -0,0 +1,30 @@ +/** + * Checks if `value` is the language type of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * **Note:** See the [ES5 spec](https://es5.github.io/#x8) for more details. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return type == 'function' || (value && type == 'object') || false; +} + +export default isObject; diff --git a/lang/isPlainObject.js b/lang/isPlainObject.js new file mode 100644 index 0000000000..9e8803c64e --- /dev/null +++ b/lang/isPlainObject.js @@ -0,0 +1,62 @@ +import isNative from './isNative'; +import shimIsPlainObject from '../internal/shimIsPlainObject'; + +/** `Object#toString` result references. */ +var objectTag = '[object Object]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** Native method references. */ +var getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf; + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * **Note:** This method assumes objects created by the `Object` constructor + * have no inherited enumerable properties. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { + if (!(value && objToString.call(value) == objectTag)) { + return false; + } + var valueOf = value.valueOf, + objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); + + return objProto + ? (value == objProto || getPrototypeOf(value) == objProto) + : shimIsPlainObject(value); +}; + +export default isPlainObject; diff --git a/lang/isRegExp.js b/lang/isRegExp.js new file mode 100644 index 0000000000..a0418eb8ef --- /dev/null +++ b/lang/isRegExp.js @@ -0,0 +1,36 @@ +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var regexpTag = '[object RegExp]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ +function isRegExp(value) { + return (isObjectLike(value) && objToString.call(value) == regexpTag) || false; +} + +export default isRegExp; diff --git a/lang/isString.js b/lang/isString.js new file mode 100644 index 0000000000..d8dc626410 --- /dev/null +++ b/lang/isString.js @@ -0,0 +1,36 @@ +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var stringTag = '[object String]'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ +function isString(value) { + return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag) || false; +} + +export default isString; diff --git a/lang/isTypedArray.js b/lang/isTypedArray.js new file mode 100644 index 0000000000..9921d37ae6 --- /dev/null +++ b/lang/isTypedArray.js @@ -0,0 +1,75 @@ +import isLength from '../internal/isLength'; +import isObjectLike from '../internal/isObjectLike'; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** Used to identify `toStringTag` values of typed arrays. */ +var typedArrayTags = {}; +typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = +typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = +typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = +typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = +typedArrayTags[uint32Tag] = true; +typedArrayTags[argsTag] = typedArrayTags[arrayTag] = +typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = +typedArrayTags[dateTag] = typedArrayTags[errorTag] = +typedArrayTags[funcTag] = typedArrayTags[mapTag] = +typedArrayTags[numberTag] = typedArrayTags[objectTag] = +typedArrayTags[regexpTag] = typedArrayTags[setTag] = +typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the `toStringTag` of values. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) + * for more details. + */ +var objToString = objectProto.toString; + +/** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ +function isTypedArray(value) { + return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false; +} + +export default isTypedArray; diff --git a/lang/isUndefined.js b/lang/isUndefined.js new file mode 100644 index 0000000000..ccff50bcb9 --- /dev/null +++ b/lang/isUndefined.js @@ -0,0 +1,21 @@ +/** + * Checks if `value` is `undefined`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ +function isUndefined(value) { + return typeof value == 'undefined'; +} + +export default isUndefined; diff --git a/lang/toArray.js b/lang/toArray.js new file mode 100644 index 0000000000..a634b9c3d2 --- /dev/null +++ b/lang/toArray.js @@ -0,0 +1,29 @@ +import arrayCopy from '../internal/arrayCopy'; +import isLength from '../internal/isLength'; +import values from '../object/values'; + +/** + * Converts `value` to an array. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3); + * // => [2, 3] + */ +function toArray(value) { + var length = value ? value.length : 0; + if (!isLength(length)) { + return values(value); + } + if (!length) { + return []; + } + return arrayCopy(value); +} + +export default toArray; diff --git a/lang/toPlainObject.js b/lang/toPlainObject.js new file mode 100644 index 0000000000..8ddb4d58f2 --- /dev/null +++ b/lang/toPlainObject.js @@ -0,0 +1,31 @@ +import baseCopy from '../internal/baseCopy'; +import keysIn from '../object/keysIn'; + +/** + * Converts `value` to a plain object flattening inherited enumerable + * properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ +function toPlainObject(value) { + return baseCopy(value, keysIn(value)); +} + +export default toPlainObject; diff --git a/lodash.js b/lodash.js new file mode 100644 index 0000000000..7ebabd3695 --- /dev/null +++ b/lodash.js @@ -0,0 +1,487 @@ +/** + * @license + * lodash 3.0.0 (Custom Build) + * Build: `lodash modularize modern exports="es" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.7.0 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +import array from './array'; +import chain from './chain'; +import collection from './collection'; +import date from './date'; +import func from './function'; +import lang from './lang'; +import number from './number'; +import object from './object'; +import string from './string'; +import utility from './utility'; +import LazyWrapper from './internal/LazyWrapper'; +import LodashWrapper from './internal/LodashWrapper'; +import arrayEach from './internal/arrayEach'; +import baseCallback from './internal/baseCallback'; +import baseForOwn from './internal/baseForOwn'; +import baseFunctions from './internal/baseFunctions'; +import isArray from './lang/isArray'; +import isObject from './lang/isObject'; +import keys from './object/keys'; +import lazyClone from './internal/lazyClone'; +import lazyReverse from './internal/lazyReverse'; +import lazyValue from './internal/lazyValue'; +import lodash from './chain/lodash'; +import matches from './utility/matches'; +import _mixin from './utility/mixin'; +import property from './utility/property'; +import support from './support'; +import thru from './chain/thru'; + +/** Used as the semantic version number. */ +var VERSION = '3.0.0'; + +/** Used to indicate the type of lazy iteratees. */ +var LAZY_FILTER_FLAG = 0, + LAZY_WHILE_FLAG = 2; + +/** Used for native method references. */ +var arrayProto = Array.prototype; + +/** Native method references. */ +var push = arrayProto.push, + unshift = arrayProto.unshift; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max, + nativeMin = Math.min; + +// wrap `_.mixin` so it works when provided only one argument +var mixin = (function(func) { + return function(object, source, options) { + if (options == null) { + var isObj = isObject(source), + props = isObj && keys(source), + methodNames = props && props.length && baseFunctions(source, props); + + if (!(methodNames ? methodNames.length : isObj)) { + options = source; + source = object; + object = this; + } + } + return func(object, source, options); + }; +}(_mixin)); + +// Add functions that return wrapped values when chaining. +lodash.after = func.after; +lodash.ary = func.ary; +lodash.assign = object.assign; +lodash.at = collection.at; +lodash.before = func.before; +lodash.bind = func.bind; +lodash.bindAll = func.bindAll; +lodash.bindKey = func.bindKey; +lodash.callback = utility.callback; +lodash.chain = chain.chain; +lodash.chunk = array.chunk; +lodash.compact = array.compact; +lodash.constant = utility.constant; +lodash.countBy = collection.countBy; +lodash.create = object.create; +lodash.curry = func.curry; +lodash.curryRight = func.curryRight; +lodash.debounce = func.debounce; +lodash.defaults = object.defaults; +lodash.defer = func.defer; +lodash.delay = func.delay; +lodash.difference = array.difference; +lodash.drop = array.drop; +lodash.dropRight = array.dropRight; +lodash.dropRightWhile = array.dropRightWhile; +lodash.dropWhile = array.dropWhile; +lodash.filter = collection.filter; +lodash.flatten = array.flatten; +lodash.flattenDeep = array.flattenDeep; +lodash.flow = func.flow; +lodash.flowRight = func.flowRight; +lodash.forEach = collection.forEach; +lodash.forEachRight = collection.forEachRight; +lodash.forIn = object.forIn; +lodash.forInRight = object.forInRight; +lodash.forOwn = object.forOwn; +lodash.forOwnRight = object.forOwnRight; +lodash.functions = object.functions; +lodash.groupBy = collection.groupBy; +lodash.indexBy = collection.indexBy; +lodash.initial = array.initial; +lodash.intersection = array.intersection; +lodash.invert = object.invert; +lodash.invoke = collection.invoke; +lodash.keys = keys; +lodash.keysIn = object.keysIn; +lodash.map = collection.map; +lodash.mapValues = object.mapValues; +lodash.matches = matches; +lodash.memoize = func.memoize; +lodash.merge = object.merge; +lodash.mixin = mixin; +lodash.negate = func.negate; +lodash.omit = object.omit; +lodash.once = func.once; +lodash.pairs = object.pairs; +lodash.partial = func.partial; +lodash.partialRight = func.partialRight; +lodash.partition = collection.partition; +lodash.pick = object.pick; +lodash.pluck = collection.pluck; +lodash.property = property; +lodash.propertyOf = utility.propertyOf; +lodash.pull = array.pull; +lodash.pullAt = array.pullAt; +lodash.range = utility.range; +lodash.rearg = func.rearg; +lodash.reject = collection.reject; +lodash.remove = array.remove; +lodash.rest = array.rest; +lodash.shuffle = collection.shuffle; +lodash.slice = array.slice; +lodash.sortBy = collection.sortBy; +lodash.sortByAll = collection.sortByAll; +lodash.take = array.take; +lodash.takeRight = array.takeRight; +lodash.takeRightWhile = array.takeRightWhile; +lodash.takeWhile = array.takeWhile; +lodash.tap = chain.tap; +lodash.throttle = func.throttle; +lodash.thru = thru; +lodash.times = utility.times; +lodash.toArray = lang.toArray; +lodash.toPlainObject = lang.toPlainObject; +lodash.transform = object.transform; +lodash.union = array.union; +lodash.uniq = array.uniq; +lodash.unzip = array.unzip; +lodash.values = object.values; +lodash.valuesIn = object.valuesIn; +lodash.where = collection.where; +lodash.without = array.without; +lodash.wrap = func.wrap; +lodash.xor = array.xor; +lodash.zip = array.zip; +lodash.zipObject = array.zipObject; + +// Add aliases. +lodash.backflow = func.flowRight; +lodash.collect = collection.map; +lodash.compose = func.flowRight; +lodash.each = collection.forEach; +lodash.eachRight = collection.forEachRight; +lodash.extend = object.assign; +lodash.iteratee = utility.callback; +lodash.methods = object.functions; +lodash.object = array.zipObject; +lodash.select = collection.filter; +lodash.tail = array.rest; +lodash.unique = array.uniq; + +// Add functions to `lodash.prototype`. +mixin(lodash, lodash); + +// Add functions that return unwrapped values when chaining. +lodash.attempt = utility.attempt; +lodash.camelCase = string.camelCase; +lodash.capitalize = string.capitalize; +lodash.clone = lang.clone; +lodash.cloneDeep = lang.cloneDeep; +lodash.deburr = string.deburr; +lodash.endsWith = string.endsWith; +lodash.escape = string.escape; +lodash.escapeRegExp = string.escapeRegExp; +lodash.every = collection.every; +lodash.find = collection.find; +lodash.findIndex = array.findIndex; +lodash.findKey = object.findKey; +lodash.findLast = collection.findLast; +lodash.findLastIndex = array.findLastIndex; +lodash.findLastKey = object.findLastKey; +lodash.findWhere = collection.findWhere; +lodash.first = array.first; +lodash.has = object.has; +lodash.identity = utility.identity; +lodash.includes = collection.includes; +lodash.indexOf = array.indexOf; +lodash.isArguments = lang.isArguments; +lodash.isArray = isArray; +lodash.isBoolean = lang.isBoolean; +lodash.isDate = lang.isDate; +lodash.isElement = lang.isElement; +lodash.isEmpty = lang.isEmpty; +lodash.isEqual = lang.isEqual; +lodash.isError = lang.isError; +lodash.isFinite = lang.isFinite; +lodash.isFunction = lang.isFunction; +lodash.isMatch = lang.isMatch; +lodash.isNaN = lang.isNaN; +lodash.isNative = lang.isNative; +lodash.isNull = lang.isNull; +lodash.isNumber = lang.isNumber; +lodash.isObject = isObject; +lodash.isPlainObject = lang.isPlainObject; +lodash.isRegExp = lang.isRegExp; +lodash.isString = lang.isString; +lodash.isTypedArray = lang.isTypedArray; +lodash.isUndefined = lang.isUndefined; +lodash.kebabCase = string.kebabCase; +lodash.last = array.last; +lodash.lastIndexOf = array.lastIndexOf; +lodash.max = collection.max; +lodash.min = collection.min; +lodash.noop = utility.noop; +lodash.now = date.now; +lodash.pad = string.pad; +lodash.padLeft = string.padLeft; +lodash.padRight = string.padRight; +lodash.parseInt = string.parseInt; +lodash.random = number.random; +lodash.reduce = collection.reduce; +lodash.reduceRight = collection.reduceRight; +lodash.repeat = string.repeat; +lodash.result = object.result; +lodash.size = collection.size; +lodash.snakeCase = string.snakeCase; +lodash.some = collection.some; +lodash.sortedIndex = array.sortedIndex; +lodash.sortedLastIndex = array.sortedLastIndex; +lodash.startsWith = string.startsWith; +lodash.template = string.template; +lodash.trim = string.trim; +lodash.trimLeft = string.trimLeft; +lodash.trimRight = string.trimRight; +lodash.trunc = string.trunc; +lodash.unescape = string.unescape; +lodash.uniqueId = utility.uniqueId; +lodash.words = string.words; + +// Add aliases. +lodash.all = collection.every; +lodash.any = collection.some; +lodash.contains = collection.includes; +lodash.detect = collection.find; +lodash.foldl = collection.reduce; +lodash.foldr = collection.reduceRight; +lodash.head = array.first; +lodash.include = collection.includes; +lodash.inject = collection.reduce; + +mixin(lodash, (function() { + var source = {}; + baseForOwn(lodash, function(func, methodName) { + if (!lodash.prototype[methodName]) { + source[methodName] = func; + } + }); + return source; +}()), false); + +// Add functions capable of returning wrapped and unwrapped values when chaining. +lodash.sample = collection.sample; + +lodash.prototype.sample = function(n) { + if (!this.__chain__ && n == null) { + return collection.sample(this.value()); + } + return this.thru(function(value) { + return collection.sample(value, n); + }); +}; + +/** + * The semantic version number. + * + * @static + * @memberOf _ + * @type string + */ +lodash.VERSION = VERSION; + +lodash.support = support; +(lodash.templateSettings = string.templateSettings).imports._ = lodash; + +// Assign default placeholders. +arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) { + lodash[methodName].placeholder = lodash; +}); + +// Add `LazyWrapper` methods that accept an `iteratee` value. +arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) { + var isFilter = index == LAZY_FILTER_FLAG; + + LazyWrapper.prototype[methodName] = function(iteratee, thisArg) { + var result = this.clone(), + filtered = result.filtered, + iteratees = result.iteratees || (result.iteratees = []); + + result.filtered = filtered || isFilter || (index == LAZY_WHILE_FLAG && result.dir < 0); + iteratees.push({ 'iteratee': baseCallback(iteratee, thisArg, 3), 'type': index }); + return result; + }; +}); + +// Add `LazyWrapper` methods for `_.drop` and `_.take` variants. +arrayEach(['drop', 'take'], function(methodName, index) { + var countName = methodName + 'Count', + whileName = methodName + 'While'; + + LazyWrapper.prototype[methodName] = function(n) { + n = n == null ? 1 : nativeMax(+n || 0, 0); + + var result = this.clone(); + if (result.filtered) { + var value = result[countName]; + result[countName] = index ? nativeMin(value, n) : (value + n); + } else { + var views = result.views || (result.views = []); + views.push({ 'size': n, 'type': methodName + (result.dir < 0 ? 'Right' : '') }); + } + return result; + }; + + LazyWrapper.prototype[methodName + 'Right'] = function(n) { + return this.reverse()[methodName](n).reverse(); + }; + + LazyWrapper.prototype[methodName + 'RightWhile'] = function(predicate, thisArg) { + return this.reverse()[whileName](predicate, thisArg).reverse(); + }; +}); + +// Add `LazyWrapper` methods for `_.first` and `_.last`. +arrayEach(['first', 'last'], function(methodName, index) { + var takeName = 'take' + (index ? 'Right': ''); + + LazyWrapper.prototype[methodName] = function() { + return this[takeName](1).value()[0]; + }; +}); + +// Add `LazyWrapper` methods for `_.initial` and `_.rest`. +arrayEach(['initial', 'rest'], function(methodName, index) { + var dropName = 'drop' + (index ? '' : 'Right'); + + LazyWrapper.prototype[methodName] = function() { + return this[dropName](1); + }; +}); + +// Add `LazyWrapper` methods for `_.pluck` and `_.where`. +arrayEach(['pluck', 'where'], function(methodName, index) { + var operationName = index ? 'filter' : 'map', + createCallback = index ? matches : property; + + LazyWrapper.prototype[methodName] = function(value) { + return this[operationName](createCallback(value)); + }; +}); + +LazyWrapper.prototype.dropWhile = function(iteratee, thisArg) { + var done, + lastIndex, + isRight = this.dir < 0; + + iteratee = baseCallback(iteratee, thisArg, 3); + return this.filter(function(value, index, array) { + done = done && (isRight ? index < lastIndex : index > lastIndex); + lastIndex = index; + return done || (done = !iteratee(value, index, array)); + }); +}; + +LazyWrapper.prototype.reject = function(iteratee, thisArg) { + iteratee = baseCallback(iteratee, thisArg, 3); + return this.filter(function(value, index, array) { + return !iteratee(value, index, array); + }); +}; + +LazyWrapper.prototype.slice = function(start, end) { + start = start == null ? 0 : (+start || 0); + var result = start < 0 ? this.takeRight(-start) : this.drop(start); + + if (typeof end != 'undefined') { + end = (+end || 0); + result = end < 0 ? result.dropRight(-end) : result.take(end - start); + } + return result; +}; + +// Add `LazyWrapper` methods to `lodash.prototype`. +baseForOwn(LazyWrapper.prototype, function(func, methodName) { + var retUnwrapped = /^(?:first|last)$/.test(methodName); + + lodash.prototype[methodName] = function() { + var value = this.__wrapped__, + args = arguments, + chainAll = this.__chain__, + isHybrid = !!this.__actions__.length, + isLazy = value instanceof LazyWrapper, + onlyLazy = isLazy && !isHybrid; + + if (retUnwrapped && !chainAll) { + return onlyLazy + ? func.call(value) + : lodash[methodName](this.value()); + } + var interceptor = function(value) { + var otherArgs = [value]; + push.apply(otherArgs, args); + return lodash[methodName].apply(lodash, otherArgs); + }; + if (isLazy || isArray(value)) { + var wrapper = onlyLazy ? value : new LazyWrapper(this), + result = func.apply(wrapper, args); + + if (!retUnwrapped && (isHybrid || result.actions)) { + var actions = result.actions || (result.actions = []); + actions.push({ 'func': thru, 'args': [interceptor], 'thisArg': lodash }); + } + return new LodashWrapper(result, chainAll); + } + return this.thru(interceptor); + }; +}); + +// Add `Array.prototype` functions to `lodash.prototype`. +arrayEach(['concat', 'join', 'pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) { + var func = arrayProto[methodName], + chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru', + retUnwrapped = /^(?:join|pop|shift)$/.test(methodName); + + lodash.prototype[methodName] = function() { + var args = arguments; + if (retUnwrapped && !this.__chain__) { + return func.apply(this.value(), args); + } + return this[chainName](function(value) { + return func.apply(value, args); + }); + }; +}); + +// Add functions to the lazy wrapper. +LazyWrapper.prototype.clone = lazyClone; +LazyWrapper.prototype.reverse = lazyReverse; +LazyWrapper.prototype.value = lazyValue; + +// Add chaining functions to the lodash wrapper. +lodash.prototype.chain = chain.wrapperChain; +lodash.prototype.reverse = chain.reverse; +lodash.prototype.toString = chain.toString; +lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = chain.value; + +// Add function aliases to the lodash wrapper. +lodash.prototype.collect = lodash.prototype.map; +lodash.prototype.head = lodash.prototype.first; +lodash.prototype.select = lodash.prototype.filter; +lodash.prototype.tail = lodash.prototype.rest; + +export default lodash; diff --git a/number.js b/number.js new file mode 100644 index 0000000000..32ff9d0a02 --- /dev/null +++ b/number.js @@ -0,0 +1,5 @@ +import random from './number/random'; + +export default { + 'random': random +}; diff --git a/number/random.js b/number/random.js new file mode 100644 index 0000000000..dcc3ea9e27 --- /dev/null +++ b/number/random.js @@ -0,0 +1,70 @@ +import baseRandom from '../internal/baseRandom'; +import isIterateeCall from '../internal/isIterateeCall'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMin = Math.min, + nativeRandom = Math.random; + +/** + * Produces a random number between `min` and `max` (inclusive). If only one + * argument is provided a number between `0` and the given number is returned. + * If `floating` is `true`, or either `min` or `max` are floats, a floating-point + * number is returned instead of an integer. + * + * @static + * @memberOf _ + * @category Number + * @param {number} [min=0] The minimum possible value. + * @param {number} [max=1] The maximum possible value. + * @param {boolean} [floating] Specify returning a floating-point number. + * @returns {number} Returns the random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ +function random(min, max, floating) { + if (floating && isIterateeCall(min, max, floating)) { + max = floating = null; + } + var noMin = min == null, + noMax = max == null; + + if (floating == null) { + if (noMax && typeof min == 'boolean') { + floating = min; + min = 1; + } + else if (typeof max == 'boolean') { + floating = max; + noMax = true; + } + } + if (noMin && noMax) { + max = 1; + noMax = false; + } + min = +min || 0; + if (noMax) { + max = min; + min = 0; + } else { + max = +max || 0; + } + if (floating || min % 1 || max % 1) { + var rand = nativeRandom(); + return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max); + } + return baseRandom(min, max); +} + +export default random; diff --git a/object.js b/object.js new file mode 100644 index 0000000000..b75fe96a8b --- /dev/null +++ b/object.js @@ -0,0 +1,53 @@ +import assign from './object/assign'; +import create from './object/create'; +import defaults from './object/defaults'; +import extend from './object/extend'; +import findKey from './object/findKey'; +import findLastKey from './object/findLastKey'; +import forIn from './object/forIn'; +import forInRight from './object/forInRight'; +import forOwn from './object/forOwn'; +import forOwnRight from './object/forOwnRight'; +import functions from './object/functions'; +import has from './object/has'; +import invert from './object/invert'; +import keys from './object/keys'; +import keysIn from './object/keysIn'; +import mapValues from './object/mapValues'; +import merge from './object/merge'; +import methods from './object/methods'; +import omit from './object/omit'; +import pairs from './object/pairs'; +import pick from './object/pick'; +import result from './object/result'; +import transform from './object/transform'; +import values from './object/values'; +import valuesIn from './object/valuesIn'; + +export default { + 'assign': assign, + 'create': create, + 'defaults': defaults, + 'extend': extend, + 'findKey': findKey, + 'findLastKey': findLastKey, + 'forIn': forIn, + 'forInRight': forInRight, + 'forOwn': forOwn, + 'forOwnRight': forOwnRight, + 'functions': functions, + 'has': has, + 'invert': invert, + 'keys': keys, + 'keysIn': keysIn, + 'mapValues': mapValues, + 'merge': merge, + 'methods': methods, + 'omit': omit, + 'pairs': pairs, + 'pick': pick, + 'result': result, + 'transform': transform, + 'values': values, + 'valuesIn': valuesIn +}; diff --git a/object/assign.js b/object/assign.js new file mode 100644 index 0000000000..92d41edd6f --- /dev/null +++ b/object/assign.js @@ -0,0 +1,35 @@ +import baseAssign from '../internal/baseAssign'; +import createAssigner from '../internal/createAssigner'; + +/** + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources overwrite property assignments of previous sources. + * If `customizer` is provided it is invoked to produce the assigned values. + * The `customizer` is bound to `thisArg` and invoked with five arguments; + * (objectValue, sourceValue, key, object, source). + * + * @static + * @memberOf _ + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize assigning values. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {Object} Returns `object`. + * @example + * + * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); + * // => { 'user': 'fred', 'age': 40 } + * + * // using a customizer callback + * var defaults = _.partialRight(_.assign, function(value, other) { + * return typeof value == 'undefined' ? other : value; + * }); + * + * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ +var assign = createAssigner(baseAssign); + +export default assign; diff --git a/object/create.js b/object/create.js new file mode 100644 index 0000000000..31f23980fa --- /dev/null +++ b/object/create.js @@ -0,0 +1,46 @@ +import baseCopy from '../internal/baseCopy'; +import baseCreate from '../internal/baseCreate'; +import isIterateeCall from '../internal/isIterateeCall'; +import keys from './keys'; + +/** + * Creates an object that inherits from the given `prototype` object. If a + * `properties` object is provided its own enumerable properties are assigned + * to the created object. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ +function create(prototype, properties, guard) { + var result = baseCreate(prototype); + if (guard && isIterateeCall(prototype, properties, guard)) { + properties = null; + } + return properties ? baseCopy(properties, result, keys(properties)) : result; +} + +export default create; diff --git a/object/defaults.js b/object/defaults.js new file mode 100644 index 0000000000..5c5fe48155 --- /dev/null +++ b/object/defaults.js @@ -0,0 +1,30 @@ +import arrayCopy from '../internal/arrayCopy'; +import assign from './assign'; +import assignDefaults from '../internal/assignDefaults'; + +/** + * Assigns own enumerable properties of source object(s) to the destination + * object for all destination properties that resolve to `undefined`. Once a + * property is set, additional defaults of the same property are ignored. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ +function defaults(object) { + if (object == null) { + return object; + } + var args = arrayCopy(arguments); + args.push(assignDefaults); + return assign.apply(undefined, args); +} + +export default defaults; diff --git a/object/extend.js b/object/extend.js new file mode 100644 index 0000000000..89b31da03b --- /dev/null +++ b/object/extend.js @@ -0,0 +1,2 @@ +import assign from './assign' +export default assign; diff --git a/object/findKey.js b/object/findKey.js new file mode 100644 index 0000000000..278362994b --- /dev/null +++ b/object/findKey.js @@ -0,0 +1,49 @@ +import baseCallback from '../internal/baseCallback'; +import baseFind from '../internal/baseFind'; +import baseForOwn from '../internal/baseForOwn'; + +/** + * This method is like `_.findIndex` except that it returns the key of the + * first element `predicate` returns truthy for, instead of the element itself. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {string|undefined} Returns the key of the matched element, else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(chr) { return chr.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // using the "_.matches" callback shorthand + * _.findKey(users, { 'age': 1 }); + * // => 'pebbles' + * + * // using the "_.property" callback shorthand + * _.findKey(users, 'active'); + * // => 'barney' + */ +function findKey(object, predicate, thisArg) { + predicate = baseCallback(predicate, thisArg, 3); + return baseFind(object, predicate, baseForOwn, true); +} + +export default findKey; diff --git a/object/findLastKey.js b/object/findLastKey.js new file mode 100644 index 0000000000..10e63fedf2 --- /dev/null +++ b/object/findLastKey.js @@ -0,0 +1,49 @@ +import baseCallback from '../internal/baseCallback'; +import baseFind from '../internal/baseFind'; +import baseForOwnRight from '../internal/baseForOwnRight'; + +/** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * If a property name is provided for `predicate` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `predicate` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {string|undefined} Returns the key of the matched element, else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(chr) { return chr.age < 40; }); + * // => returns `pebbles` assuming `_.findKey` returns `barney` + * + * // using the "_.matches" callback shorthand + * _.findLastKey(users, { 'age': 36 }); + * // => 'barney' + * + * // using the "_.property" callback shorthand + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ +function findLastKey(object, predicate, thisArg) { + predicate = baseCallback(predicate, thisArg, 3); + return baseFind(object, predicate, baseForOwnRight, true); +} + +export default findLastKey; diff --git a/object/forIn.js b/object/forIn.js new file mode 100644 index 0000000000..2052d09b65 --- /dev/null +++ b/object/forIn.js @@ -0,0 +1,39 @@ +import baseFor from '../internal/baseFor'; +import bindCallback from '../internal/bindCallback'; +import keysIn from './keysIn'; + +/** + * Iterates over own and inherited enumerable properties of an object invoking + * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked + * with three arguments; (value, key, object). Iterator functions may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forIn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) + */ +function forIn(object, iteratee, thisArg) { + if (typeof iteratee != 'function' || typeof thisArg != 'undefined') { + iteratee = bindCallback(iteratee, thisArg, 3); + } + return baseFor(object, iteratee, keysIn); +} + +export default forIn; diff --git a/object/forInRight.js b/object/forInRight.js new file mode 100644 index 0000000000..422b2cbeaf --- /dev/null +++ b/object/forInRight.js @@ -0,0 +1,35 @@ +import baseForRight from '../internal/baseForRight'; +import bindCallback from '../internal/bindCallback'; +import keysIn from './keysIn'; + +/** + * This method is like `_.forIn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forInRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' + */ +function forInRight(object, iteratee, thisArg) { + iteratee = bindCallback(iteratee, thisArg, 3); + return baseForRight(object, iteratee, keysIn); +} + +export default forInRight; diff --git a/object/forOwn.js b/object/forOwn.js new file mode 100644 index 0000000000..461c7d9bcf --- /dev/null +++ b/object/forOwn.js @@ -0,0 +1,31 @@ +import baseForOwn from '../internal/baseForOwn'; +import bindCallback from '../internal/bindCallback'; + +/** + * Iterates over own enumerable properties of an object invoking `iteratee` + * for each property. The `iteratee` is bound to `thisArg` and invoked with + * three arguments; (value, key, object). Iterator functions may exit iteration + * early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) { + * console.log(key); + * }); + * // => logs '0', '1', and 'length' (iteration order is not guaranteed) + */ +function forOwn(object, iteratee, thisArg) { + if (typeof iteratee != 'function' || typeof thisArg != 'undefined') { + iteratee = bindCallback(iteratee, thisArg, 3); + } + return baseForOwn(object, iteratee); +} + +export default forOwn; diff --git a/object/forOwnRight.js b/object/forOwnRight.js new file mode 100644 index 0000000000..22d349d1cc --- /dev/null +++ b/object/forOwnRight.js @@ -0,0 +1,28 @@ +import baseForRight from '../internal/baseForRight'; +import bindCallback from '../internal/bindCallback'; +import keys from './keys'; + +/** + * This method is like `_.forOwn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns `object`. + * @example + * + * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(n, key) { + * console.log(key); + * }); + * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length' + */ +function forOwnRight(object, iteratee, thisArg) { + iteratee = bindCallback(iteratee, thisArg, 3); + return baseForRight(object, iteratee, keys); +} + +export default forOwnRight; diff --git a/object/functions.js b/object/functions.js new file mode 100644 index 0000000000..44a730d6fe --- /dev/null +++ b/object/functions.js @@ -0,0 +1,23 @@ +import baseFunctions from '../internal/baseFunctions'; +import keysIn from './keysIn'; + +/** + * Creates an array of function property names from all enumerable properties, + * own and inherited, of `object`. + * + * @static + * @memberOf _ + * @alias methods + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the new array of property names. + * @example + * + * _.functions(_); + * // => ['all', 'any', 'bind', ...] + */ +function functions(object) { + return baseFunctions(object, keysIn(object)); +} + +export default functions; diff --git a/object/has.js b/object/has.js new file mode 100644 index 0000000000..82b88dbd6e --- /dev/null +++ b/object/has.js @@ -0,0 +1,26 @@ +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Checks if `key` exists as a direct property of `object` instead of an + * inherited property. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @param {string} key The key to check. + * @returns {boolean} Returns `true` if `key` is a direct property, else `false`. + * @example + * + * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); + * // => true + */ +function has(object, key) { + return object ? hasOwnProperty.call(object, key) : false; +} + +export default has; diff --git a/object/invert.js b/object/invert.js new file mode 100644 index 0000000000..afcaffe55d --- /dev/null +++ b/object/invert.js @@ -0,0 +1,62 @@ +import isIterateeCall from '../internal/isIterateeCall'; +import keys from './keys'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite property + * assignments of previous values unless `multiValue` is `true`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to invert. + * @param {boolean} [multiValue] Allow multiple values per key. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Object} Returns the new inverted object. + * @example + * + * _.invert({ 'first': 'fred', 'second': 'barney' }); + * // => { 'fred': 'first', 'barney': 'second' } + * + * // without `multiValue` + * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }); + * // => { 'fred': 'third', 'barney': 'second' } + * + * // with `multiValue` + * _.invert({ 'first': 'fred', 'second': 'barney', 'third': 'fred' }, true); + * // => { 'fred': ['first', 'third'], 'barney': ['second'] } + */ +function invert(object, multiValue, guard) { + if (guard && isIterateeCall(object, multiValue, guard)) { + multiValue = null; + } + var index = -1, + props = keys(object), + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index], + value = object[key]; + + if (multiValue) { + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + } + else { + result[value] = key; + } + } + return result; +} + +export default invert; diff --git a/object/keys.js b/object/keys.js new file mode 100644 index 0000000000..cf2d57d268 --- /dev/null +++ b/object/keys.js @@ -0,0 +1,48 @@ +import isLength from '../internal/isLength'; +import isNative from '../lang/isNative'; +import isObject from '../lang/isObject'; +import shimKeys from '../internal/shimKeys'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys; + +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys) + * for more details. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +var keys = !nativeKeys ? shimKeys : function(object) { + if (object) { + var Ctor = object.constructor, + length = object.length; + } + if ((typeof Ctor == 'function' && Ctor.prototype === object) || + (typeof object != 'function' && (length && isLength(length)))) { + return shimKeys(object); + } + return isObject(object) ? nativeKeys(object) : []; +}; + +export default keys; diff --git a/object/keysIn.js b/object/keysIn.js new file mode 100644 index 0000000000..34f0b9510d --- /dev/null +++ b/object/keysIn.js @@ -0,0 +1,65 @@ +import isArguments from '../lang/isArguments'; +import isArray from '../lang/isArray'; +import isIndex from '../internal/isIndex'; +import isLength from '../internal/isLength'; +import isObject from '../lang/isObject'; +import support from '../support'; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { + if (object == null) { + return []; + } + if (!isObject(object)) { + object = Object(object); + } + var length = object.length; + length = (length && isLength(length) && + (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0; + + var Ctor = object.constructor, + index = -1, + isProto = typeof Ctor == 'function' && Ctor.prototype == object, + result = Array(length), + skipIndexes = length > 0; + + while (++index < length) { + result[index] = (index + ''); + } + for (var key in object) { + if (!(skipIndexes && isIndex(key, length)) && + !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; +} + +export default keysIn; diff --git a/object/mapValues.js b/object/mapValues.js new file mode 100644 index 0000000000..929fa09c79 --- /dev/null +++ b/object/mapValues.js @@ -0,0 +1,50 @@ +import baseCallback from '../internal/baseCallback'; +import baseForOwn from '../internal/baseForOwn'; + +/** + * Creates an object with the same keys as `object` and values generated by + * running each own enumerable property of `object` through `iteratee`. The + * iteratee function is bound to `thisArg` and invoked with three arguments; + * (value, key, object). + * + * If a property name is provided for `iteratee` the created "_.property" + * style callback returns the property value of the given element. + * + * If an object is provided for `iteratee` the created "_.matches" style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. If a property name or object is provided it is used to + * create a "_.property" or "_.matches" style callback respectively. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the new mapped object. + * @example + * + * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(n) { return n * 3; }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * // using the "_.property" callback shorthand + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ +function mapValues(object, iteratee, thisArg) { + var result = {}; + iteratee = baseCallback(iteratee, thisArg, 3); + + baseForOwn(object, function(value, key, object) { + result[key] = iteratee(value, key, object); + }); + return result; +} + +export default mapValues; diff --git a/object/merge.js b/object/merge.js new file mode 100644 index 0000000000..16186a5210 --- /dev/null +++ b/object/merge.js @@ -0,0 +1,52 @@ +import baseMerge from '../internal/baseMerge'; +import createAssigner from '../internal/createAssigner'; + +/** + * Recursively merges own enumerable properties of the source object(s), that + * don't resolve to `undefined` into the destination object. Subsequent sources + * overwrite property assignments of previous sources. If `customizer` is + * provided it is invoked to produce the merged values of the destination and + * source properties. If `customizer` returns `undefined` merging is handled + * by the method instead. The `customizer` is bound to `thisArg` and invoked + * with five arguments; (objectValue, sourceValue, key, object, source). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize merging properties. + * @param {*} [thisArg] The `this` binding of `customizer`. + * @returns {Object} Returns `object`. + * @example + * + * var users = { + * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] + * }; + * + * var ages = { + * 'data': [{ 'age': 36 }, { 'age': 40 }] + * }; + * + * _.merge(users, ages); + * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } + * + * // using a customizer callback + * var object = { + * 'fruits': ['apple'], + * 'vegetables': ['beet'] + * }; + * + * var other = { + * 'fruits': ['banana'], + * 'vegetables': ['carrot'] + * }; + * + * _.merge(object, other, function(a, b) { + * return _.isArray(a) ? a.concat(b) : undefined; + * }); + * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } + */ +var merge = createAssigner(baseMerge); + +export default merge; diff --git a/object/methods.js b/object/methods.js new file mode 100644 index 0000000000..265229eb35 --- /dev/null +++ b/object/methods.js @@ -0,0 +1,2 @@ +import functions from './functions' +export default functions; diff --git a/object/omit.js b/object/omit.js new file mode 100644 index 0000000000..a6d0fa5542 --- /dev/null +++ b/object/omit.js @@ -0,0 +1,51 @@ +import arrayMap from '../internal/arrayMap'; +import baseDifference from '../internal/baseDifference'; +import baseFlatten from '../internal/baseFlatten'; +import bindCallback from '../internal/bindCallback'; +import keysIn from './keysIn'; +import pickByArray from '../internal/pickByArray'; +import pickByCallback from '../internal/pickByCallback'; + +/** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable properties of `object` that are not omitted. + * Property names may be specified as individual arguments or as arrays of + * property names. If `predicate` is provided it is invoked for each property + * of `object` omitting the properties `predicate` returns truthy for. The + * predicate is bound to `thisArg` and invoked with three arguments; + * (value, key, object). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|...(string|string[])} [predicate] The function invoked per + * iteration or property names to omit, specified as individual property + * names or arrays of property names. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.omit(object, 'age'); + * // => { 'user': 'fred' } + * + * _.omit(object, _.isNumber); + * // => { 'user': 'fred' } + */ +function omit(object, predicate, thisArg) { + if (object == null) { + return {}; + } + if (typeof predicate != 'function') { + var props = arrayMap(baseFlatten(arguments, false, false, 1), String); + return pickByArray(object, baseDifference(keysIn(object), props)); + } + predicate = bindCallback(predicate, thisArg, 3); + return pickByCallback(object, function(value, key, object) { + return !predicate(value, key, object); + }); +} + +export default omit; diff --git a/object/pairs.js b/object/pairs.js new file mode 100644 index 0000000000..394d469322 --- /dev/null +++ b/object/pairs.js @@ -0,0 +1,30 @@ +import keys from './keys'; + +/** + * Creates a two dimensional array of the key-value pairs for `object`, + * e.g. `[[key1, value1], [key2, value2]]`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the new array of key-value pairs. + * @example + * + * _.pairs({ 'barney': 36, 'fred': 40 }); + * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) + */ +function pairs(object) { + var index = -1, + props = keys(object), + length = props.length, + result = Array(length); + + while (++index < length) { + var key = props[index]; + result[index] = [key, object[key]]; + } + return result; +} + +export default pairs; diff --git a/object/pick.js b/object/pick.js new file mode 100644 index 0000000000..b49109e60b --- /dev/null +++ b/object/pick.js @@ -0,0 +1,41 @@ +import baseFlatten from '../internal/baseFlatten'; +import bindCallback from '../internal/bindCallback'; +import pickByArray from '../internal/pickByArray'; +import pickByCallback from '../internal/pickByCallback'; + +/** + * Creates an object composed of the picked `object` properties. Property + * names may be specified as individual arguments or as arrays of property + * names. If `predicate` is provided it is invoked for each property of `object` + * picking the properties `predicate` returns truthy for. The predicate is + * bound to `thisArg` and invoked with three arguments; (value, key, object). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|...(string|string[])} [predicate] The function invoked per + * iteration or property names to pick, specified as individual property + * names or arrays of property names. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.pick(object, 'user'); + * // => { 'user': 'fred' } + * + * _.pick(object, _.isString); + * // => { 'user': 'fred' } + */ +function pick(object, predicate, thisArg) { + if (object == null) { + return {}; + } + return typeof predicate == 'function' + ? pickByCallback(object, bindCallback(predicate, thisArg, 3)) + : pickByArray(object, baseFlatten(arguments, false, false, 1)); +} + +export default pick; diff --git a/object/result.js b/object/result.js new file mode 100644 index 0000000000..2198d5f4ca --- /dev/null +++ b/object/result.js @@ -0,0 +1,41 @@ +import isFunction from '../lang/isFunction'; + +/** + * Resolves the value of property `key` on `object`. If the value of `key` is + * a function it is invoked with the `this` binding of `object` and its result + * is returned, else the property value is returned. If the property value is + * `undefined` the `defaultValue` is used in its place. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {string} key The key of the property to resolve. + * @param {*} [defaultValue] The value returned if the property value + * resolves to `undefined`. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'user': 'fred', 'age': _.constant(40) }; + * + * _.result(object, 'user'); + * // => 'fred' + * + * _.result(object, 'age'); + * // => 40 + * + * _.result(object, 'status', 'busy'); + * // => 'busy' + * + * _.result(object, 'status', _.constant('busy')); + * // => 'busy' + */ +function result(object, key, defaultValue) { + var value = object == null ? undefined : object[key]; + if (typeof value == 'undefined') { + value = defaultValue; + } + return isFunction(value) ? value.call(object) : value; +} + +export default result; diff --git a/object/transform.js b/object/transform.js new file mode 100644 index 0000000000..dfbfff41af --- /dev/null +++ b/object/transform.js @@ -0,0 +1,62 @@ +import arrayEach from '../internal/arrayEach'; +import baseCallback from '../internal/baseCallback'; +import baseCreate from '../internal/baseCreate'; +import baseForOwn from '../internal/baseForOwn'; +import isArray from '../lang/isArray'; +import isObject from '../lang/isObject'; +import isTypedArray from '../lang/isTypedArray'; + +/** + * An alternative to `_.reduce`; this method transforms `object` to a new + * `accumulator` object which is the result of running each of its own enumerable + * properties through `iteratee`, with each invocation potentially mutating + * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked + * with four arguments; (accumulator, value, key, object). Iterator functions + * may exit iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @category Object + * @param {Array|Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The custom accumulator value. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {*} Returns the accumulated value. + * @example + * + * var squares = _.transform([1, 2, 3, 4, 5, 6], function(result, n) { + * n *= n; + * if (n % 2) { + * return result.push(n) < 3; + * } + * }); + * // => [1, 9, 25] + * + * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, n, key) { + * result[key] = n * 3; + * }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + */ +function transform(object, iteratee, accumulator, thisArg) { + var isArr = isArray(object) || isTypedArray(object); + iteratee = baseCallback(iteratee, thisArg, 4); + + if (accumulator == null) { + if (isArr || isObject(object)) { + var Ctor = object.constructor; + if (isArr) { + accumulator = isArray(object) ? new Ctor : []; + } else { + accumulator = baseCreate(typeof Ctor == 'function' && Ctor.prototype); + } + } else { + accumulator = {}; + } + } + (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) { + return iteratee(accumulator, value, index, object); + }); + return accumulator; +} + +export default transform; diff --git a/object/values.js b/object/values.js new file mode 100644 index 0000000000..a1c7d62872 --- /dev/null +++ b/object/values.js @@ -0,0 +1,33 @@ +import baseValues from '../internal/baseValues'; +import keys from './keys'; + +/** + * Creates an array of the own enumerable property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ +function values(object) { + return baseValues(object, keys(object)); +} + +export default values; diff --git a/object/valuesIn.js b/object/valuesIn.js new file mode 100644 index 0000000000..c766fd0620 --- /dev/null +++ b/object/valuesIn.js @@ -0,0 +1,31 @@ +import baseValues from '../internal/baseValues'; +import keysIn from './keysIn'; + +/** + * Creates an array of the own and inherited enumerable property values + * of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.valuesIn(new Foo); + * // => [1, 2, 3] (iteration order is not guaranteed) + */ +function valuesIn(object) { + return baseValues(object, keysIn(object)); +} + +export default valuesIn; diff --git a/package.json b/package.json new file mode 100644 index 0000000000..18882ede19 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "lodash-es", + "version": "3.0.0", + "description": "The modern build of lodash exported as ES modules.", + "homepage": "https://lodash.com/custom-builds", + "license": "MIT", + "jsnext:main": "lodash.js", + "keywords": "es6, modules, stdlib, util", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Benjamin Tan (https://d10.github.io/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (https://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": "lodash/lodash", + "scripts": { "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" } +} diff --git a/string.js b/string.js new file mode 100644 index 0000000000..0eb9d89a67 --- /dev/null +++ b/string.js @@ -0,0 +1,47 @@ +import camelCase from './string/camelCase'; +import capitalize from './string/capitalize'; +import deburr from './string/deburr'; +import endsWith from './string/endsWith'; +import escape from './string/escape'; +import escapeRegExp from './string/escapeRegExp'; +import kebabCase from './string/kebabCase'; +import pad from './string/pad'; +import padLeft from './string/padLeft'; +import padRight from './string/padRight'; +import parseInt from './string/parseInt'; +import repeat from './string/repeat'; +import snakeCase from './string/snakeCase'; +import startsWith from './string/startsWith'; +import template from './string/template'; +import templateSettings from './string/templateSettings'; +import trim from './string/trim'; +import trimLeft from './string/trimLeft'; +import trimRight from './string/trimRight'; +import trunc from './string/trunc'; +import unescape from './string/unescape'; +import words from './string/words'; + +export default { + 'camelCase': camelCase, + 'capitalize': capitalize, + 'deburr': deburr, + 'endsWith': endsWith, + 'escape': escape, + 'escapeRegExp': escapeRegExp, + 'kebabCase': kebabCase, + 'pad': pad, + 'padLeft': padLeft, + 'padRight': padRight, + 'parseInt': parseInt, + 'repeat': repeat, + 'snakeCase': snakeCase, + 'startsWith': startsWith, + 'template': template, + 'templateSettings': templateSettings, + 'trim': trim, + 'trimLeft': trimLeft, + 'trimRight': trimRight, + 'trunc': trunc, + 'unescape': unescape, + 'words': words +}; diff --git a/string/camelCase.js b/string/camelCase.js new file mode 100644 index 0000000000..529d14a932 --- /dev/null +++ b/string/camelCase.js @@ -0,0 +1,28 @@ +import createCompounder from '../internal/createCompounder'; + +/** + * Converts `string` to camel case. + * See [Wikipedia](https://en.wikipedia.org/wiki/CamelCase) for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the camel cased string. + * @example + * + * _.camelCase('Foo Bar'); + * // => 'fooBar' + * + * _.camelCase('--foo-bar'); + * // => 'fooBar' + * + * _.camelCase('__foo_bar__'); + * // => 'fooBar' + */ +var camelCase = createCompounder(function(result, word, index) { + word = word.toLowerCase(); + return index ? (result + word.charAt(0).toUpperCase() + word.slice(1)) : word; +}); + +export default camelCase; diff --git a/string/capitalize.js b/string/capitalize.js new file mode 100644 index 0000000000..307f663244 --- /dev/null +++ b/string/capitalize.js @@ -0,0 +1,21 @@ +import baseToString from '../internal/baseToString'; + +/** + * Capitalizes the first character of `string`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * _.capitalize('fred'); + * // => 'Fred' + */ +function capitalize(string) { + string = baseToString(string); + return string && (string.charAt(0).toUpperCase() + string.slice(1)); +} + +export default capitalize; diff --git a/string/deburr.js b/string/deburr.js new file mode 100644 index 0000000000..53d0b9562a --- /dev/null +++ b/string/deburr.js @@ -0,0 +1,27 @@ +import baseToString from '../internal/baseToString'; +import deburrLetter from '../internal/deburrLetter'; + +/** Used to match latin-1 supplementary letters (excluding mathematical operators). */ +var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g; + +/** + * Deburrs `string` by converting latin-1 supplementary letters to basic latin letters. + * See [Wikipedia](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) + * for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to deburr. + * @returns {string} Returns the deburred string. + * @example + * + * _.deburr('déjà vu'); + * // => 'deja vu' + */ +function deburr(string) { + string = baseToString(string); + return string && string.replace(reLatin1, deburrLetter); +} + +export default deburr; diff --git a/string/endsWith.js b/string/endsWith.js new file mode 100644 index 0000000000..de586fe4c5 --- /dev/null +++ b/string/endsWith.js @@ -0,0 +1,36 @@ +import baseToString from '../internal/baseToString'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMin = Math.min; + +/** + * Checks if `string` ends with the given target string. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to search. + * @param {string} [target] The string to search for. + * @param {number} [position=string.length] The position to search from. + * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`. + * @example + * + * _.endsWith('abc', 'c'); + * // => true + * + * _.endsWith('abc', 'b'); + * // => false + * + * _.endsWith('abc', 'b', 2); + * // => true + */ +function endsWith(string, target, position) { + string = baseToString(string); + target = (target + ''); + + var length = string.length; + position = (typeof position == 'undefined' ? length : nativeMin(position < 0 ? 0 : (+position || 0), length)) - target.length; + return position >= 0 && string.indexOf(target, position) == position; +} + +export default endsWith; diff --git a/string/escape.js b/string/escape.js new file mode 100644 index 0000000000..f497cd8364 --- /dev/null +++ b/string/escape.js @@ -0,0 +1,48 @@ +import baseToString from '../internal/baseToString'; +import escapeHtmlChar from '../internal/escapeHtmlChar'; + +/** Used to match HTML entities and HTML characters. */ +var reUnescapedHtml = /[&<>"'`]/g, + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + +/** + * Converts the characters "&", "<", ">", '"', "'", and '`', in `string` to + * their corresponding HTML entities. + * + * **Note:** No other characters are escaped. To escape additional characters + * use a third-party library like [_he_](https://mths.be/he). + * + * Though the ">" character is escaped for symmetry, characters like + * ">" and "/" don't require escaping in HTML and have no special meaning + * unless they're part of a tag or unquoted attribute value. + * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * (under "semi-related fun fact") for more details. + * + * Backticks are escaped because in Internet Explorer < 9, they can break out + * of attribute values or HTML comments. See [#102](https://html5sec.org/#102), + * [#108](https://html5sec.org/#108), and [#133](https://html5sec.org/#133) of + * the [HTML5 Security Cheatsheet](https://html5sec.org/) for more details. + * + * When working with HTML you should always quote attribute values to reduce + * XSS vectors. See [Ryan Grove's article](http://wonko.com/post/html-escaping) + * for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ +function escape(string) { + // Reset `lastIndex` because in IE < 9 `String#replace` does not. + string = baseToString(string); + return (string && reHasUnescapedHtml.test(string)) + ? string.replace(reUnescapedHtml, escapeHtmlChar) + : string; +} + +export default escape; diff --git a/string/escapeRegExp.js b/string/escapeRegExp.js new file mode 100644 index 0000000000..6c98e65549 --- /dev/null +++ b/string/escapeRegExp.js @@ -0,0 +1,32 @@ +import baseToString from '../internal/baseToString'; + +/** + * Used to match `RegExp` special characters. + * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special) + * for more details. + */ +var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, + reHasRegExpChars = RegExp(reRegExpChars.source); + +/** + * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*", + * "+", "(", ")", "[", "]", "{" and "}" in `string`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https://lodash\.com/\)' + */ +function escapeRegExp(string) { + string = baseToString(string); + return (string && reHasRegExpChars.test(string)) + ? string.replace(reRegExpChars, '\\$&') + : string; +} + +export default escapeRegExp; diff --git a/string/kebabCase.js b/string/kebabCase.js new file mode 100644 index 0000000000..36e3cfffb7 --- /dev/null +++ b/string/kebabCase.js @@ -0,0 +1,28 @@ +import createCompounder from '../internal/createCompounder'; + +/** + * Converts `string` to kebab case (a.k.a. spinal case). + * See [Wikipedia](https://en.wikipedia.org/wiki/Letter_case#Computers) for + * more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the kebab cased string. + * @example + * + * _.kebabCase('Foo Bar'); + * // => 'foo-bar' + * + * _.kebabCase('fooBar'); + * // => 'foo-bar' + * + * _.kebabCase('__foo_bar__'); + * // => 'foo-bar' + */ +var kebabCase = createCompounder(function(result, word, index) { + return result + (index ? '-' : '') + word.toLowerCase(); +}); + +export default kebabCase; diff --git a/string/pad.js b/string/pad.js new file mode 100644 index 0000000000..685107f7a8 --- /dev/null +++ b/string/pad.js @@ -0,0 +1,51 @@ +import baseToString from '../internal/baseToString'; +import createPad from '../internal/createPad'; +import root from '../internal/root'; + +/** Native method references. */ +var ceil = Math.ceil, + floor = Math.floor; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsFinite = root.isFinite; + +/** + * Pads `string` on the left and right sides if it is shorter then the given + * padding length. The `chars` string may be truncated if the number of padding + * characters can't be evenly divided by the padding length. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.pad('abc', 8); + * // => ' abc ' + * + * _.pad('abc', 8, '_-'); + * // => '_-abc_-_' + * + * _.pad('abc', 3); + * // => 'abc' + */ +function pad(string, length, chars) { + string = baseToString(string); + length = +length; + + var strLength = string.length; + if (strLength >= length || !nativeIsFinite(length)) { + return string; + } + var mid = (length - strLength) / 2, + leftLength = floor(mid), + rightLength = ceil(mid); + + chars = createPad('', rightLength, chars); + return chars.slice(0, leftLength) + string + chars; +} + +export default pad; diff --git a/string/padLeft.js b/string/padLeft.js new file mode 100644 index 0000000000..afae0aad83 --- /dev/null +++ b/string/padLeft.js @@ -0,0 +1,32 @@ +import baseToString from '../internal/baseToString'; +import createPad from '../internal/createPad'; + +/** + * Pads `string` on the left side if it is shorter then the given padding + * length. The `chars` string may be truncated if the number of padding + * characters exceeds the padding length. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padLeft('abc', 6); + * // => ' abc' + * + * _.padLeft('abc', 6, '_-'); + * // => '_-_abc' + * + * _.padLeft('abc', 3); + * // => 'abc' + */ +function padLeft(string, length, chars) { + string = baseToString(string); + return string && (createPad(string, length, chars) + string); +} + +export default padLeft; diff --git a/string/padRight.js b/string/padRight.js new file mode 100644 index 0000000000..e7bc4efb27 --- /dev/null +++ b/string/padRight.js @@ -0,0 +1,32 @@ +import baseToString from '../internal/baseToString'; +import createPad from '../internal/createPad'; + +/** + * Pads `string` on the right side if it is shorter then the given padding + * length. The `chars` string may be truncated if the number of padding + * characters exceeds the padding length. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padRight('abc', 6); + * // => 'abc ' + * + * _.padRight('abc', 6, '_-'); + * // => 'abc_-_' + * + * _.padRight('abc', 3); + * // => 'abc' + */ +function padRight(string, length, chars) { + string = baseToString(string); + return string && (string + createPad(string, length, chars)); +} + +export default padRight; diff --git a/string/parseInt.js b/string/parseInt.js new file mode 100644 index 0000000000..7a547c851d --- /dev/null +++ b/string/parseInt.js @@ -0,0 +1,68 @@ +import isIterateeCall from '../internal/isIterateeCall'; +import root from '../internal/root'; +import trim from './trim'; + +/** Used to detect hexadecimal string values. */ +var reHexPrefix = /^0[xX]/; + +/** Used to detect and test for whitespace. */ +var whitespace = ( + // Basic whitespace characters. + ' \t\x0b\f\xa0\ufeff' + + + // Line terminators. + '\n\r\u2028\u2029' + + + // Unicode category "Zs" space separators. + '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000' +); + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeParseInt = root.parseInt; + +/** + * Converts `string` to an integer of the specified radix. If `radix` is + * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal, + * in which case a `radix` of `16` is used. + * + * **Note:** This method aligns with the ES5 implementation of `parseInt`. + * See the [ES5 spec](https://es5.github.io/#E) for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} string The string to convert. + * @param {number} [radix] The radix to interpret `value` by. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {number} Returns the converted integer. + * @example + * + * _.parseInt('08'); + * // => 8 + * + * _.map(['6', '08', '10'], _.parseInt); + * // => [6, 8, 10] + */ +function parseInt(string, radix, guard) { + if (guard && isIterateeCall(string, radix, guard)) { + radix = 0; + } + return nativeParseInt(string, radix); +} +// Fallback for environments with pre-ES5 implementations. +if (nativeParseInt(whitespace + '08') != 8) { + parseInt = function(string, radix, guard) { + // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`. + // Chrome fails to trim leading whitespace characters. + // See https://code.google.com/p/v8/issues/detail?id=3109 for more details. + if (guard ? isIterateeCall(string, radix, guard) : radix == null) { + radix = 0; + } else if (radix) { + radix = +radix; + } + string = trim(string); + return nativeParseInt(string, radix || (reHexPrefix.test(string) ? 16 : 10)); + }; +} + +export default parseInt; diff --git a/string/repeat.js b/string/repeat.js new file mode 100644 index 0000000000..600415f55b --- /dev/null +++ b/string/repeat.js @@ -0,0 +1,50 @@ +import baseToString from '../internal/baseToString'; +import root from '../internal/root'; + +/** Native method references. */ +var floor = Math.floor; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsFinite = root.isFinite; + +/** + * Repeats the given string `n` times. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to repeat. + * @param {number} [n=0] The number of times to repeat the string. + * @returns {string} Returns the repeated string. + * @example + * + * _.repeat('*', 3); + * // => '***' + * + * _.repeat('abc', 2); + * // => 'abcabc' + * + * _.repeat('abc', 0); + * // => '' + */ +function repeat(string, n) { + var result = ''; + string = baseToString(string); + n = +n; + if (n < 1 || !string || !nativeIsFinite(n)) { + return result; + } + // Leverage the exponentiation by squaring algorithm for a faster repeat. + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. + do { + if (n % 2) { + result += string; + } + n = floor(n / 2); + string += string; + } while (n); + + return result; +} + +export default repeat; diff --git a/string/snakeCase.js b/string/snakeCase.js new file mode 100644 index 0000000000..78c7128798 --- /dev/null +++ b/string/snakeCase.js @@ -0,0 +1,27 @@ +import createCompounder from '../internal/createCompounder'; + +/** + * Converts `string` to snake case. + * See [Wikipedia](https://en.wikipedia.org/wiki/Snake_case) for more details. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the snake cased string. + * @example + * + * _.snakeCase('Foo Bar'); + * // => 'foo_bar' + * + * _.snakeCase('--foo-bar'); + * // => 'foo_bar' + * + * _.snakeCase('fooBar'); + * // => 'foo_bar' + */ +var snakeCase = createCompounder(function(result, word, index) { + return result + (index ? '_' : '') + word.toLowerCase(); +}); + +export default snakeCase; diff --git a/string/startsWith.js b/string/startsWith.js new file mode 100644 index 0000000000..94723f802f --- /dev/null +++ b/string/startsWith.js @@ -0,0 +1,33 @@ +import baseToString from '../internal/baseToString'; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeMin = Math.min; + +/** + * Checks if `string` starts with the given target string. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to search. + * @param {string} [target] The string to search for. + * @param {number} [position=0] The position to search from. + * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`. + * @example + * + * _.startsWith('abc', 'a'); + * // => true + * + * _.startsWith('abc', 'b'); + * // => false + * + * _.startsWith('abc', 'b', 1); + * // => true + */ +function startsWith(string, target, position) { + string = baseToString(string); + position = position == null ? 0 : nativeMin(position < 0 ? 0 : (+position || 0), string.length); + return string.lastIndexOf(target, position) == position; +} + +export default startsWith; diff --git a/string/template.js b/string/template.js new file mode 100644 index 0000000000..8b3e85729f --- /dev/null +++ b/string/template.js @@ -0,0 +1,229 @@ +import assignOwnDefaults from '../internal/assignOwnDefaults'; +import attempt from '../utility/attempt'; +import baseAssign from '../internal/baseAssign'; +import baseToString from '../internal/baseToString'; +import baseValues from '../internal/baseValues'; +import escapeStringChar from '../internal/escapeStringChar'; +import isError from '../lang/isError'; +import isIterateeCall from '../internal/isIterateeCall'; +import keys from '../object/keys'; +import reInterpolate from '../internal/reInterpolate'; +import templateSettings from './templateSettings'; + +/** Used to match empty string literals in compiled template source. */ +var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + +/** + * Used to match ES template delimiters. + * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literal-lexical-components) + * for more details. + */ +var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + +/** Used to ensure capturing order of template delimiters. */ +var reNoMatch = /($^)/; + +/** Used to match unescaped characters in compiled string literals. */ +var reUnescapedString = /['\n\r\u2028\u2029\\]/g; + +/** + * Creates a compiled template function that can interpolate data properties + * in "interpolate" delimiters, HTML-escape interpolated data properties in + * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data + * properties may be accessed as free variables in the template. If a setting + * object is provided it takes precedence over `_.templateSettings` values. + * + * **Note:** In the development build `_.template` utilizes sourceURLs for easier debugging. + * See the [HTML5 Rocks article on sourcemaps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) + * for more details. + * + * For more information on precompiling templates see + * [lodash's custom builds documentation](https://lodash.com/custom-builds). + * + * For more information on Chrome extension sandboxes see + * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The template string. + * @param {Object} [options] The options object. + * @param {RegExp} [options.escape] The HTML "escape" delimiter. + * @param {RegExp} [options.evaluate] The "evaluate" delimiter. + * @param {Object} [options.imports] An object to import into the template as free variables. + * @param {RegExp} [options.interpolate] The "interpolate" delimiter. + * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. + * @param {string} [options.variable] The data object variable name. + * @param- {Object} [otherOptions] Enables the legacy `options` param signature. + * @returns {Function} Returns the compiled template function. + * @example + * + * // using the "interpolate" delimiter to create a compiled template + * var compiled = _.template('hello <%= user %>!'); + * compiled({ 'user': 'fred' }); + * // => 'hello fred!' + * + * // using the HTML "escape" delimiter to escape data property values + * var compiled = _.template('<%- value %>'); + * compiled({ 'value': '